서론
해당 포스트는 Combine
의 예외 처리에 대해 정리한 내용입니다.
tryMap
일반적으로 Publisher
는 예외를 던지지 못합니다. 아래 코드에서 컴파일 에러가 발생합니다.
enum CustomError: Error {
case operationFailed
}
let pub = [1, 2, 3, 4, 5].publisher
let cancellable = pub
.map { // 컴파일 에러!!! No exact matches in call to instance method 'map'
if $0 == 3 {
throw CustomError.operationFailed
}
return $0
}.sink {
print($0)
}
예외처리를 위해서는 map 대신 tryMap
을 사용해야합니다. 추가적으로 예외를 받아서 처리해야하는 코드를 작성해야합니다.
catch
예외가 발생했을 시 예외처리를 위한 가장 기본적인 방법은 catch
연산자를 사용하는 것입니다.
enum CustomError: Error {
case operationFailed
}
let pub = [1, 2, 3, 4, 5].publisher
let cancellable = pub
.tryMap {
if $0 == 3 {
throw CustomError.operationFailed
}
return $0
}
.catch { error in
print("Error: \(error)")
return Just(-1) // 예외가 발생하면 예외를 처리하고 새로운 값을 방출해야한다. 그리고 새로운 값은 방출되지 않는다.
}.sink { value in
print("Value: \(value)")
}
replaceError
replaceError
연산자는 예외가 발생했을 때 대체 값을 방출합니다. catch 연산자보다 더 간단하게 사용할 수 있습니다.
let cancellable = pub
.tryMap {
if $0 == 3 {
throw CustomError.operationFailed
}
return $0
}
.replaceError(with: -1) // -1 을 방출하고 Publisher 를 종료한다.
.sink {
print($0)
}
위 코드는 catch
와 동일한 결과를 반환합니다.
retry
retry
연산자는 예외가 발생했을 때, 지정된 횟수만큼 재시도합니다.
let pub = [1, 2, 3, 4, 5].publisher
let cancellable = pub
.tryMap {
if $0 == 3 {
throw CustomError.operationFailed
}
return $0
}
.retry(2)
.sink { completion in // 반드시 completion 을 받아야합니다.
print(completion)
} receiveValue: {
print($0)
}
// 1
// 2
// 1
// 2
// 1
// 2
// failure(__lldb_expr_87.CustomError.operationFailed) , 두번 재시도했지만 실패
retry 를 사용할때 반드시 sink 에서 completion 을 받아야합니다. 그렇지 않으면 컴파일 에러가 발생합니다.
댓글남기기