관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - Swift] 2. Swift Concurrency 개념 - async, await를 이용하여 api 호출해보기 본문

iOS 응용 (swift)

[iOS - Swift] 2. Swift Concurrency 개념 - async, await를 이용하여 api 호출해보기

jake-kim 2022. 12. 3. 22:21

1. Swift Concurrency 개념 - async, await, Task, async let, Actor

2. Swift Concurrency 개념 - async, await를 이용하여 api 호출해보기

Async, Await 없는 API 호출

  • 모델 준비
struct AlbumResult: Codable {
  let results: [Album]
}

struct Album: Codable, Hashable {
  let collectionId: Int
  let collectionName: String
  let collectionPrice: Double
}
  • 구현
enum APIError: Error {
  case invalidURL
  case noData
}

enum API {
  static func fetchAlbums(completion: @escaping (Result<AlbumResult, Error>) -> Void) {
    guard let url = URL(string: "https://itunes.apple.com/search?term=taylor+swift&entity=album") else {
      completion(.failure(APIError.invalidURL))
      return
    }
    
    URLSession.shared.dataTask(with: url) { data, _, error in
      if let error = error {
        completion(.failure(error))
        return
      }
      
      guard let data = data else {
        completion(.failure(APIError.noData))
        return
      }
      
      do {
        let result = try JSONDecoder().decode(AlbumResult.self, from: data)
        completion(.success(result))
      } catch {
        completion(.failure(error))
      }
      
    }
    .resume()
  }
}
  • 사용하는쪽
API.fetchAlbums { result in
  switch result {
  case let .success(response):
    print(response)
  case let .failure(error):
    print(error)
  }
}

Async, Await를 사용한 경우

  • URLSession앞에 await 키워드를 붙여서 편리하게 사용이 가능
    • 스위프트에서 URLSession 확장으로 구현되어 있는걸 활용
@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
extension URLSession {
    public func data(for request: URLRequest, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)
    public func data(from url: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)
    public func upload(for request: URLRequest, fromFile fileURL: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)
    public func upload(for request: URLRequest, from bodyData: Data, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)
    public func download(for request: URLRequest, delegate: URLSessionTaskDelegate? = nil) async throws -> (URL, URLResponse)
    public func download(from url: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (URL, URLResponse)
    public func download(resumeFrom resumeData: Data, delegate: URLSessionTaskDelegate? = nil) async throws -> (URL, URLResponse)
}
  • API 정의
    • completion handler가 없기 때문에 더욱 깔끔한 코드
    • URLSession.shaed.data(from:) 앞에 await 키워드를 붙여서 사용
  // MARK: Async & Await
  static func fetchAlbums() async throws -> AlbumResult {
    guard let url = URL(string: "https://itunes.apple.com/search?term=taylor+swift&entity=album") else {
      throw APIError.invalidURL
    }
    let (data, _) = try await URLSession.shared.data(from: url)
    let result = try JSONDecoder().decode(AlbumResult.self, from: data)
    return result
  }
  • 사용하는 쪽
// async await
Task {
  do {
    let result = try await API.fetchAlbums()
    print(result)
  } catch {
    print(error)
  }
}

비교 not async await vs async await

  • API 정의 부분

 

  • 사용하는쪽

* 전체 코드: https://github.com/JK0369/ExAsyncAwaitAPI

* 참고

https://betterprogramming.pub/making-network-requests-with-async-await-in-swift-6b5880c9df6a

 

Comments