[swift] Swift에서 비동기 작업에서의 에러 처리 방법

비동기 작업은 앱 개발시 매우 중요한 요소입니다. 이런 작업이 발생할 때 발생하는 에러를 처리하는 방법은 프로그램의 안정성을 보장하고 사용자 경험을 향상시키는 데 큰 영향을 줍니다. 이번 글에서는 Swift에서 비동기 작업에서 에러를 처리하는 방법에 대해 알아보겠습니다.

1. do-try-catch 블록을 사용하기

Swift에서 에러 처리를 위해 사용되는 주요 구조 중 하나는 do-try-catch 블록입니다. 비동기 작업에서 에러를 처리하기 위해서는 비동기 작업을 수행하는 클로저에서 do-try-catch 블록을 사용해야 합니다.

다음은 클로저에서 do-try-catch 블록을 사용하여 비동기 작업에서 발생한 에러를 처리하는 간단한 예제 코드입니다.

func performAsyncTask(completion: @escaping (Error?) -> Void) {
    DispatchQueue.global().async {
        do {
            // 비동기 작업 수행
        } catch let error {
            // 에러 처리
            completion(error)
        }
    }
}

// 사용 예시
performAsyncTask { error in
    if let error = error {
        print("에러 발생: \(error.localizedDescription)")
    } else {
        print("작업 성공!")
    }
}

2. Result 타입 활용하기

Swift 5부터는 Result 타입이 추가되어 비동기 작업에서의 에러 처리를 보다 명확하게 할 수 있게 되었습니다. Result 타입은 성공한 값을 나타내는 Success와 실패한 값을 나타내는 Failure의 두 가지 값을 가질 수 있는 열거형입니다.

다음은 Result 타입을 활용하여 비동기 작업에서 에러를 처리하는 예제 코드입니다.

func performAsyncTask(completion: @escaping (Result<Void, Error>) -> Void) {
    DispatchQueue.global().async {
        do {
            // 비동기 작업 수행
            completion(.success(()))
        } catch let error {
            // 에러 처리
            completion(.failure(error))
        }
    }
}

// 사용 예시
performAsyncTask { result in
    switch result {
    case .success:
        print("작업 성공!")
    case .failure(let error):
        print("에러 발생: \(error.localizedDescription)")
    }
}

3. Combine 프레임워크 활용하기

Swift에서 비동기 작업을 보다 효과적으로 처리하기 위해 Combine 프레임워크를 사용할 수도 있습니다. Combine은 Swift 5에서 추가된 비동기적인 이벤트와 데이터 스트림을 다루기 위한 프레임워크로, 에러 처리를 위한 다양한 기능을 제공합니다.

Combine을 사용하여 비동기 작업에서 에러를 처리하는 예제 코드는 다음과 같습니다.

import Combine

enum CustomError: Error {
    case networkError
    case parsingError
}

func performAsyncTask() -> AnyPublisher<Void, Error> {
    return Future<Void, Error> { promise in
        DispatchQueue.global().async {
            do {
                // 비동기 작업 수행
                promise(.success(()))
            } catch {
                // 에러 처리
                promise(.failure(CustomError.networkError))
            }
        }
    }
    .eraseToAnyPublisher()
}

// 사용 예시
performAsyncTask()
    .sink(receiveCompletion: { completion in
        switch completion {
        case .finished:
            print("작업 성공!")
        case .failure(let error):
            print("에러 발생: \(error.localizedDescription)")
        }
    }, receiveValue: { value in
        // 처리된 값
    })

참고