✅ 이번시간에는 서버에서 API를 받아와서 파싱까지 하는 것을 알아보자!
✅ 이번시간에 알아볼 코드는 아래와 같은 코드이다.
class SearchAPI {
static func search(_ term: String, completion: @escaping ([Movie]) -> Void) { // completion 클로저를 사용하기 위한 방법
// 이스케이핑이 있으면 함수가 종료되고 나서 실행
let session = URLSession(configuration: .default) // 1. 세션 만들기
var urlComponents = URLComponents(string: "https://itunes.apple.com/search?")!
let mediaQuery = URLQueryItem(name: "media", value: "movie")
let entityQuery = URLQueryItem(name: "entity", value: "movie")
let termQuery = URLQueryItem(name: "term", value: term)
urlComponents.queryItems?.append(mediaQuery)
urlComponents.queryItems?.append(entityQuery)
urlComponents.queryItems?.append(termQuery)
let requestURL = urlComponents.url! // 2. url 구성
let dataTask = session.dataTask(with: requestURL) { data, response, error in
let successRange = 200..<300
guard error == nil,
let statusCode = (response as? HTTPURLResponse)?.statusCode,
successRange.contains(statusCode) else {
// 에러가 없고, 상태코드에 응답에 대한 HTTPURLResponse에서 찾아 할당하고, 상태코드가 범위 안에 포함된다면 스무스하게 넘어가고
// 그렇지 않으면 completion을 빈 배열을 준다
completion([]) // completion부분에 아무것도 정보를 담지 않는다.
return
}
guard let resultData = data else {
// 위의 error이 없는걸 확인했고, dataTask의 data를 결과테이터 변수에 대입하는데, 이 작업이 실패하면 completion에 빈배열 주고 리턴
completion([])
return
}
let movies = SearchAPI.parseMovies(resultData) //
completion(movies)
}
dataTask.resume() // 3. resume으로 데이터 받아오기
}
static func parseMovies(_ data: Data) -> [Movie] { // 타입메소드로 선언
let decoder = JSONDecoder() // 1. 디코더 선언하고
do {
let response = try decoder.decode(Response.self, from: data) // data로부터 Response타입으로 디코딩!
let movies = response.movies
return movies
} catch let error {
print("--> parsing error: \(error.localizedDescription)")
return []
}
}
}
struct Response: Codable {
let resultCount: Int
let movies: [Movie]
enum CodingKeys: String, CodingKey {
case resultCount
case movies = "results"
}
}
struct Movie: Codable {
let title: String
let director: String
let thumbnailPath: String
let previewURL: String
enum CodingKeys: String, CodingKey {
case title = "trackName"
case director = "artistName"
case thumbnailPath = "artworkUrl100"
case previewURL = "previewUrl"
}
}
우선 search 쪽에서 URL 세션을 통해 구성하는 모습을 볼 수 있어.
그 다음에 dataTask 쪽인데 볼까?
우선 successRange는 HTTP 응답코드에서 200번대가 성공적인 응답이라서 저렇게 범위를 정한거야.
그 다음에는 에러가 없고, 응답코드가 성공적인 번호에 속하면 guard 문을 지나가야겠지?
그 다음에 데이터를 변수에 대입해서 그 받아온 데이터를 파싱하는 함수로 보내주면 돼.
그 다음은 parseMovie 쪽인데 스태틱 메소드라 인스턴스(객체)를 생성하지 않아도 돼.
❗️ 그리고 제일 중요한게 resume 꼭 작성해줘야 코드가 작동하니까.. 잊지말기!
✅ parseMovie 쪽이 이제 진짜 parsing 부분이야.
1. 반환할 데이터 타입을 명시하고( 함수 선언부에 )
2. JSONDecoder를 대입하고 ( JSON 파일 디코딩 할 예정이라서 )
3. decoder.decode를 통해 파싱을 어떻게 할건지 간략하게 정해주는데 ( try를 사용하는건 이유는 이 작업이 실패할 수도 있기 때문에 )
--> 실패하면 catch로 이동
decode의 파라미터에 대해서 알아보면
첫번째 파라미터는 어떤 형식으로 바꿀건가
두번째 파라미터(from)는 바꿀 데이터는 어떤건지
즉 from A to B (A에서부터 B로) 의 의미로 생각해보면 이해가 쉽다.
4. 우리가 필요한건 movies인데, 응답받아온거를 다 쓰는게 아니라, 그 중에서 movies에 대한 정보만 필요함으로 그에 맞게끔 변환해준 모습이야.
📡 내가 예시에서 사용한 데이터에서 JSON 트리 구성된걸 참고하여 사용하였다.
5. 우리가 가져온 데이터를 movies의 형태로 리턴!
var movies: [Movie] = [] // 다른 viewController에서 선언되어 있는 형태
위에 이런 식으로 선언되어 있다!
✅ CodingKey 저 부분은 Codable을 사용할 때, 서버에서 내려준 key와 우리가 선언한 변수명이 같아야만 에러가 나지 않는데, 우리가 원하는 변수명으로 바꿔줄 때 저 코드를 사용한다.
❗️ 코딩키 쪽에 s 잘못 붙여서 에러 많이 내는데,,, 이거 스스로 주의하자...
(추가)
JSONSerializaition을 쓰는 경우가 있는데, 여기 예제에서는 JSON에서 하나의 key:value만 필요하니까 이게 필요 없었지만 만약 JSON을 딕셔너리 형태로 변환해서 여러개의 데이터를 배열식으로 관리해야하면 이 코드가 꼭 들어가야한다.
이에 대한 부분이 포스팅을 참고하기
'Archive > 패캠(올인원)' 카테고리의 다른 글
ch17 SPM과 CocoaPod 충돌시 해결 (0) | 2021.07.02 |
---|---|
ch17 나의 ScrollView Guide! 상하좌우!! (0) | 2021.06.29 |
ch15 escaping과 non-escaping 클로저에 대해서 알아보자 (0) | 2021.06.29 |
🍜 ch15 인스턴스 메소드 vs 타입메소드 (0) | 2021.06.29 |
📡 ch14 URLSession (feat. Codable) (0) | 2021.06.28 |