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

Swift는 강력한 비동기 프로그래밍 모델을 제공하여 개발자가 비동기 작업을 쉽게 처리할 수 있도록 도와줍니다. 비동기 작업을 수행하는 동안 발생할 수 있는 예외를 적절히 처리하는 것은 중요한 과제입니다. 이번 글에서는 Swift에서의 비동기 작업 예외 처리 방법을 비교해 보겠습니다.

1. Result 타입 사용

Swift에서는 비동기 작업의 결과를 처리하기 위해 Result 타입을 제공합니다. 이 타입은 작업의 성공과 실패를 나타낼 수 있으며, 에러 정보를 포함할 수도 있습니다. 비동기 작업이 완료되면 Result 타입으로 결과를 반환하고, 코드에서 이를 처리할 수 있습니다.

func loadData(completion: @escaping (Result<Data, Error>) -> Void) {
    // 비동기 작업 수행
    // ...
    
    // 작업이 성공한 경우
    if let data = data {
        completion(.success(data))
    }
    
    // 작업이 실패한 경우
    else {
        completion(.failure(Error()))
    }
}

작업이 성공하면 .success case에 결과 데이터를 전달하고, 실패하면 .failure case에 에러를 전달합니다. 이후 작업 결과를 처리하는 코드에서 switch문을 사용하여 성공과 실패를 처리할 수 있습니다.

loadData { result in
    switch result {
    case .success(let data):
        // 데이터 처리
    case .failure(let error):
        // 에러 처리
    }
}

2. async/await 사용 (Swift 5.5 이상)

Swift 5.5부터 비동기 작업을 더 쉽게 처리하기 위해 async/await 문법이 도입되었습니다. 이를 사용하면 작성한 코드가 동기적으로 실행되는 것처럼 보이지만, 실제로는 비동기적으로 작업이 처리됩니다. async 키워드를 사용하여 비동기 작업을 정의하고, await 키워드를 사용하여 작업의 결과를 기다릴 수 있습니다.

func loadData() async throws -> Data {
    // 비동기 작업 수행
    // ...
    
    // 작업이 성공한 경우
    if let data = data {
        return data
    }
    
    // 작업이 실패한 경우
    else {
        throw Error()
    }
}

비동기 함수에서 throws 키워드를 사용하여 에러를 던질 수 있으며, 호출하는 쪽에서 try 키워드를 사용하여 에러를 처리할 수 있습니다.

do {
    let data = try await loadData()
    // 데이터 처리
} catch {
    // 에러 처리
}

3. Combine 프레임워크 사용

Combine은 Swift 5에서 소개된 반응형 프로그래밍을 위한 프레임워크입니다. Combine을 사용하면 비동기 작업의 결과를 스트림으로 처리할 수 있으며, 에러 처리도 쉽게 할 수 있습니다.

func loadData() -> AnyPublisher<Data, Error> {
    // 비동기 작업 수행
    // ...
    
    // 작업이 성공한 경우
    if let data = data {
        return Just(data)
            .setFailureType(to: Error.self)
            .eraseToAnyPublisher()
    }
    
    // 작업이 실패한 경우
    else {
        return Fail(error: Error())
            .eraseToAnyPublisher()
    }
}

AnyPublisher 타입을 사용하여 비동기 작업의 결과를 스트림으로 만들 수 있습니다. 작업이 성공한 경우 Just 연산자를 사용하고, 실패한 경우 Fail 연산자를 사용하여 에러를 발생시킬 수 있습니다. 작업 결과를 처리하는 코드에서는 sink 메서드를 사용하여 스트림의 값을 받아 처리할 수 있습니다.

loadData()
    .sink(receiveCompletion: { completion in
        switch completion {
        case .finished:
            // 완료 처리
        case .failure(let error):
            // 에러 처리
        }
    }, receiveValue: { data in
        // 데이터 처리
    })

결론

Swift에서 비동기 작업의 예외 처리는 Result 타입, async/await, 또는 Combine 프레임워크를 사용하여 처리할 수 있습니다. 각각의 방법은 다른 사용법과 특징을 가지고 있으니, 개발 상황이나 요구에 맞게 적절한 방법을 선택하여 사용하면 됩니다.