huequad / interview

1 stars 0 forks source link

async, await #21

Open lenaios opened 3 years ago

lenaios commented 3 years ago

async, await in iOS 15+

sync vs async

import UIKit

// 1. 이미지 String -> URLRequest
// 2. URLSession.shared.dataTask -> Data
// 3. Data -> UIImage
// 4. UIImage -> UIImage
enum FetchError: Error {
  case badID
  case badImage
}

func fetchThumbnail(for id: String, completion: @escaping (UIImage?, Error?) -> Void) {
  // 1
  let url = URL(string: id)!
  let request = URLRequest(url: url)
  // 2
  let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
      completion(nil, error)
    } else if (response as? HTTPURLResponse)?.statusCode != 200 {
      completion(nil, FetchError.badID)
    } else {
      // 3
      guard let image = UIImage(data: data!) else {
        completion(nil, FetchError.badID)
        return
      }
      // 4
      image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
        guard let thumbnail = thumbnail else {
           return // potential bug
        }
        completion(thumbnail, nil)
      }
    }
  }
  task.resume()
}

// 이렇게 작성하면 guard를 통과하지 못할 경우에 바로 return 시 디버깅의 어려움
// async/await 사용해서 코드를 변경해보자
// completion 삭제, error는 throws

func fetchThumbnail(for id: String) async throws -> UIImage {
  let url = URL(string: id)!
  let request = URLRequest(url: url)
  // async throws 함수는 try await와 함께 사용되야 한다.
  let (data, response) = try await URLSession.shared.data(for: request)
  guard (response as? HTTPURLResponse)?.statusCode == 200 else {
    throw FetchError.badID
  }
  let image = UIImage(data: data)
  guard let thumbnail = await image?.byPreparingThumbnail(ofSize: CGSize(width: 40, height: 40)) else {
    throw FetchError.badImage
  }
  return thumbnail
}

// 코드가 짧아지고 가독성이 좋아짐
// 언제 실행될 지 몰라 completion으로 클로저를 넘기던 방식에서 동기스럽게 코드가 바뀌었다.