Async Await 활용하기

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를 사용하면 어느시점에 에러가 났는지도 가독성 있게 체크가 가능하다.