let url = "http://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=\(APIKey.boxOfficeKey)&targetDt=20120101"
AF.request(url, method: .get).validate().responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
case .failure(let error):
print(error)
}
}
.failure(let error)
에서 print(error)
로AF.request(url, method: .get, headers: header)
.validate(statusCode: 200...500) // 200 ~ 500 사이를 모두 success라고 한다
.responseJSON{ response in
switch response.result {
case .success(let value) :
let json = JSON(
print(json)
주의해야 할 점은, 이 때 들어온 json
은 statusCode가 200이 아닐 때의 값이 들어올 수 있기 때문에
무작정 성공 케이스의 json 형태만 보고 접근하면 안된다.
에러 내용을 확인하고 끝내야 한다
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
let statusCode = response.response?.statusCode ?? 500
// 성공(200)인 경우 작업 시작
if (statusCode == 200) {
Info
-> App Transport Security Settings
Allow Arbitrary Loads
-> YES.gitignore
파일 생성.gitignore
커밋맨 처음(서버 통신 전)에는 보일 필요가 없다
override func viewDidLoad() {
super.viewDidLoad()
indicatorView.isHidden = true
}
서버에 요청 들어가자마자 보이게 하고, 빙글빙글 시작
func callRequest(_ query: String) {
// 요청 들어간다
indicatorView.startAnimating()
indicatorView.isHidden = false
응답 성공적으로 받았으면 다시 숨기고, 빙글빙글 끝
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
/* 데이터 들어온걸로 할거 하고 */
// 이제 숨겨
self.indicatorView.stopAnimating()
self.indicatorView.isHidden = true
self.movieTableView.reloadData()
APIManager
파일을 하나 만들고, api를 호출하는 코드를 여기서 작성한다completionHandler
를 이용한다 (@escaping
사용)URL+Extension.swift
카카오에서 제공하는 api를 이용할 때, 여러 api 링크의 앞은 동일하므로 baseURL로 저장해둔다
// URL+Extension.swift
// 0807sesac
//
// Created by 임승섭 on 2023/08/11.
//
import Foundation
// URL은 구조체이기 때문에 확장 가능
extension URL {
static let baseURL = "https://dapi.kakao.com/v2/search/"
static func makeEndPointString(_ endpoint: String) -> String {
return baseURL + endpoint
}
}
EndPoint.swift
원하는 분야(?)의 api 주소를 뒤에 붙여줄 때, enum으로 처리한다
기존에 만들어뒀던 타입 메서드를 활용한다
// EndPoint.swift
// 0807sesac
//
// Created by 임승섭 on 2023/08/11.
//
import Foundation
enum Endpoint {
case blog
case cafe
case video
var requestURL: String {
switch self {
case .blog: return URL.makeEndPointString("blog?query=??")
//return URL.baseURL + "blog?query=??"
case .cafe: return URL.makeEndPointString("cafe?query=??")
case .video: return URL.makeEndPointString("vclip?query=")
}
}
}
KakaoAPIManager.swift
api 호출하는 코드를 따로 파일을 만들어서 작성한다
// KakaoAPIManager.swift
// 0807sesac
//
// Created by 임승섭 on 2023/08/11.
//
import Foundation
import Alamofire
import SwiftyJSON
class KakaoAPIManager {
// 인스턴스 생성은 shared 하나만 할 수 있게 막아둠
static let shared = KakaoAPIManager()
private init() {}
let header: HTTPHeaders = ["Authorization": APIKey.kakaoKey]
// 어떤 분야(type), 필요한 문자열(검색)(query), 데이터로 할 일(completionHandler)
func callRequest(type: Endpoint, query: String, completionHandler: @escaping (JSON) -> () ) {
// 문자열은 반드시 encoding 해서 query에 넣어준다
guard let text = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return }
// 분야에 대한 url까지 requestURL을 통해 호출하고
// 뒤에 필요한 문자열을 붙여준다 -> 최종 url
let url = type.requestURL + text
AF.request(url, method: .get, headers: header)
.validate()
.responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
// json을 잘 받아왔으면, 이제 그거가지고 할 일은 얘를 호출하는 곳에서 진행한다 -> completionHandler
completionHandler(json)
case .failure(let error):
print(error)
}
}
}
}
VideoViewController.swift
기존에 api 요청했던 함수에서는 APIManager
에서 만든 callRequest
함수를 호출하고,
매개변수로 들어가는 클로저에 원하는 코드를 작성한다
func callRequest(query: String, page: Int) {
KakaoAPIManager.shared.callRequest(type: .video, query: query) { json in
/* json으로 할 일 작성 */
}
}
withIdentifier
에 대한 값을 문자열로 적어야 한다enum으로 모든 클래스를 케이스로 정리하였다.
identifier는 모두 클래스 이름 그대로 썼기 때문에 String rawValue로 뽑으면
literal한 문자열을 얻을 수 있다.
// About.swift
enum Identifier: String {
case SelectViewController
case SelectCollectionViewCell
case DetailSelectViewController
case MainViewController
case SettingViewController
case SettingTableViewCell
case ModifyNameViewController
case ChangeTamaViewController
case DetailChangeTamaViewController
}
// rawValue로 뽑아서 사용했다
let vc = self.storyboard?.instantiateViewController(withIdentifier: Identifier.SelectViewController.rawValue) as! SelectViewController
프로토콜의 타입 연산 프로퍼티를 사용한다
타입 저장 프로퍼티는 그때마다 값을 업데이트해주어야 하는 로직이 필요하기 때문에 연산 프로퍼티를 사용했다
// ReusableViewProtocol.swift
import Foundation
import UIKit
protocol ReusableViewProtocol {
static var identifier: String { get }
}
extension UIViewController: ReusableViewProtocol {
static var identifier: String {
return String(describing: self)
}
}
extension UITableViewCell: ReusableViewProtocol {
static var identifier: String {
return String(describing: self)
}
}
// 타입 연산 프로퍼티를 실행시켜서 문자열을 뽑는다
guard let cell = tableView.dequeueReusableCell(withIdentifier: VideoTableViewCell.identifier ) as? VideoTableViewCell else { return UITableViewCell() }
Userdefaults.standard
가 너무 많아서 보기 안좋았다// UserDefaultsHelper.swift
import Foundation
class UserDefaultsHelper {
static let standard = UserDefaultsHelper()
private init() {} // 생성자에 외부에서 접근하지 못하게 한다
// -> 외부에서 이 클래스에 대한 인스턴스 생성 불가능
let userDefaults = UserDefaults.standard
enum Key: String {
case nickname, age
}
var nickname: String {
get {
userDefaults.string(forKey: Key.nickname.rawValue) ?? "대장"
}
set {
userDefaults.set(newValue, forKey: Key.nickname.rawValue)
}
}
var age: Int {
get {
return userDefaults.integer(forKey: Key.age.rawValue)
}
set {
userDefaults.set(newValue, forKey: Key.age.rawValue)
}
}
}
간단하게만 정리
간단하게만 정리
// imageView의 모양을 원으로 만들기 위해 cornerRadius를 조정해준다
// (1) 해당 이미지뷰(정사각형)의 width의 절반만큼 cornerRadius 값을 주면 된다
// (2) 현재 스토리보드 상에서 이미지뷰의 width는 기기 사이즈에 대한 비율로 잡아져 있다
// 당연히 순서는 (2)가 끝나고 (1)로 가야 한다
/* 일반적인 생각 */
@IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.layer.cornerRadius = imageView.frame.width / 2
}
// 요렇게 하면 (2)보다 (1)이 먼저 실행되어 버리고, 이 때 코드 상의 frame은 스토리보드 기준으로 임의로 잡아버린다
// 따라서 다른 기기로 앱을 실행시켜도 스토리보드에서 14pro로 작업했으면 모든 크기가 14pro 기준으로 잡히기 때문에
// 완벽한 원을 확인할 수 없다
/* DispatchQueue.main.async 사용*/
@IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
self.imageView.layer.cornerRadius
= self.imageView.frame.width / 2
}
}
// main.async로 (1)을 뒤로 보내버린다
// 굿
@IBAction func buttonClicked(_ sender: UIButton) {
// 1. url -> 2. data -> 3. image
// 이 중 2가 시간이 오래걸리기 때문에, 2 3을 다른 알바생한테 던진다
// 그래서 1 끝나고도 화면 만질 수 있도록 한다
// 주의해야 할 점은, image는 UI 관련이기 때문에 다시 main으로 돌려줘야 한다
let url = URL(string: "https://api.nasa.gov/assets/img/general/apod.jpg")!
DispatchQueue.global().async { // 매니저에게 애들한테 골고루 나눠주라고 함, 그리고 애들한테는 바로 다음 작업 시작하라고 함
let data = try! Data(contentsOf: url)
// 다시 메인에다가 넣어줘야 해 (UI 관련된거)
DispatchQueue.main.async {
self.firstImageView.image = UIImage(data: data)
}
}
}
훌륭한 글 감사드립니다.