Async Await 활용하기
Swift 5.5에서 추가된 async, await은 Swift Concurrency Model로 비동기 작업을 동기 작업처럼 처리할 수 기능을 제공한다.
기존에 Completion Handler 를 이용할 때에, 뎁스가 길어지고, 뎁스가 길어짐에 따라 조건 분기가 복잡해지며 결국 가독성이 떨어지고 유지보수 하는데에 어려움을 겪게 된다.
만약 3개의 API를 순차적으로 호출할 건데, success 했을 때 다음 API를 호출하는 형식의 예라고 생각해보자
import Foundation
let apiURL1 = URL(string: "더미 API1 URL")!
let apiURL2 = URL(string: "더미 API2 URL")!
let apiURL3 = URL(string: "더미 API3 URL")!
func fetchAPI(url: URL, completion: @escaping (Result<Data, Error>) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
if let data = data {
completion(.success(data))
}
}
task.resume()
}
func executeAPIs() {
fetchAPI(url: apiURL1) { result1 in
switch result1 {
case .success:
fetchAPI(url: apiURL2) { result2 in
switch result2 {
case .success:
fetchAPI(url: apiURL3) { result3 in
switch result3 {
case .success(let data):
print("All APIs succeeded, final data: \(data)")
case .failure(let error):
print("Unexpected error")
}
}
case .failure(let error):
print("Unexpected error")
}
}
case .failure(let error):
print("Unexpected error")
}
}
}
excuteAPIs 호출 시에, 뎁스가 깊어지는 것을 볼 수 있고, 각 뎁스마다 에러케이스를 체크해서 호출해야 해서 가독성과 유지보수성이 떨어진다.
import Foundation
let apiURL1 = URL(string: "더미 API1 URL")!
let apiURL2 = URL(string: "더미 API2 URL")!
let apiURL3 = URL(string: "더미 API3 URL")!
func fetchAPI(url: URL) async throws -> Data {
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
func executeAPIs() async {
do {
_ = try await fetchAPI(url: apiURL1)
_ = try await fetchAPI(url: apiURL2)
let finalData = try await fetchAPI(url: apiURL3)
} catch {
print("Unexpected error")
}
}이런 형식으로 do - catch문으로 failed 됐을 때 에러를 핸들링 할 수 있다. 또 throw를 사용하면 어느시점에 에러가 났는지도 가독성 있게 체크가 가능하다.