- 비동기 코드를 일반 코드처럼 쓰자.
- 동기와 비동기
- 동기: 호출하면 스레드가 그 작업을 끝낼때까지 블록 된다.
- 비동기: 호출하면 다른 스레드가 작업을 하고, 해당 스레드는 그동안 다른 작업이 가능하다.
- Completion Handler등으로 결과를 받는다.
- 비동기 호출이 필요한 작업은 보통 무거운 작업이다.
- completionHandler의 문제점
- 호출하는 것을 잊기 쉽다. 특히 오류 상황에서. 비동기 상황에서는 에러를 던지는 것도 안된다.
- 호출하는 부분이 여러군데 흩뿌려지기 때문에 더 이해하기 어렵다.
- result 타입이 있으면 좀 더 간결해지지만 그래도 쉽지 않다.
- async가 있다면, 이러한 호출을 선형적으로 만들 수 있다.
- 동기 메소드에서 쓰던 에러 처리 기법 등을 그대로 쓸 수 있다.
func fetchThumbnail(for id: String) -> async throws -> UIImage {
let request = thumbnailURLRequest(for: id)
let (data, response) = try await URLSession.shared.data(for: request)
guard (response as? HTTPURLResponse)?.status == 200 else { throw FetchError.badID }
let maybeImage = UIImage(data: data)
guard let thumbnail = await maybeImage?.thumbnail else { throw FetchError.badImage }
return thumbnail
}
- async 프로퍼티 → get-only 프로퍼티만 적용 가능
extension UIImage {
var thumbnail: UIImage? {
get async {
let size = CGSize(width: 40, height: 40)
// thumbnail화
}
}
}
- for-loop에서도 적용 가능 → async-sequence 참조
- 함수 호출 구조
- async를 만나면, 해당 작업은 시스템에서 실행하고, 해당 함수의 이후 실행은 블록 된다.
- 이에 async만 가능한 suspending이라는 기법이 동원된다. → 코루틴이네
- await를 하면 그때까지 스레드가 블록된다.
- await를 호출하지 않는 작업들은 그대로 호출된다.
- async가 반환되면, 이후 작업이 실행된다.
- async/await의 활용
- async는 그 특성상 그것을 호출하는 코드도 async여야 한다.
- 그래서 있는게 async 블록이다. 동기 메소드에서 비동기 메소드를 호출하려면 이 안에서 호출하면 된다.
- 표준 라이브러리의 많은 API가 이에 대응한다.
- completion handler를 사용하는 패턴을 대체할 수 있다.
- 기존 메소드를 async로 대체하기 위해 continuation이라는 기능을 사용할 수 있다. → 마이그레이션 용도 인 듯
- 모든 패스에서 반드시 작업을 실행시켜야 한다.
- 여러번 실행시켜도 안된다.