# catchError, catchErrorJustReturn
옵저버블 처리 과정에서 에러가 발생한 경우 이에 대한 처리가 필요하다. RxSwift에서는 catchError
라는 연산자를 통해 에러 발생시 디폴트값을 사용하거나 새로운 옵저버블로 대체하는 방식을 사용한다. next
이벤트나 completed
이벤트는 구독자에게 그대로 전달한다.
혹은 retry
를 통해 에러 발생이 없을때까지 옵저버블에 재요청을 한다거나 한계치를 설정하여 해당 횟수까지만 재요청을 진행할 수도 있다.
catchError
는 클로저를 갖는다. 클로저 파라미터에 에러가 전달된 경우 옵저버블을 리턴하여 계속해서 구독자에게 다른 이벤트들을 정상적으로 방출할 수 있게 해준다.
enum MyError: Error {
case error
}
let subject = PublishSubject<Int>()
let recovery = PublishSubject<Int>()
subject
.catch{ _ in recovery } // 에러 catch
.subscribe { print($0) }
.disposed(by: bag)
subject.onError(MyError.error)
recovery.onNext(3)
recovery.onCompleted()
트레일링 클로저
위의 코드에서 catch{ a in recovery }
는 아래 코드와 같다.
subject
.catch{ _ in // 와일드카드 패턴으로 작성된 파라미터는 Error타입
return recovery
}
소스 옵저버블에서 에러를 한번 리턴하게 되면 이후로 더 이상 이벤트 방출이 불가능하다.
catchAndReturn
연산자는 에러 발생시 기본값을 리턴하며 해당 값은 소스 옵저버블의 타입을 그대로 따른다.
enum MyError: Error {
case error
}
let subject = PublishSubject<Int>()
subject
.catchAndReturn(3)
.subscribe { print($0) } // next(3) 이후 completed
.disposed(by: bag)
subject.onError(MyError.error)
# retry
retry
연산자는 빈 파라미터를 갖고 생성하거나, maxAttemptCount
값을 지정하여 생성할 수 있다. 해당 파라미터는 retry
최대 시도횟수를 지정한다.
이 값은 최대 시도횟수 + 1
로 지정하여 전달해야 의도대로 동작한다고 설명에 나와있다.
var attempts = 1 // 최대 시도 횟수를 변수로 관리
let source = Observable<Int>.create { observer in
let currentAttempts = attempts
print("#\(currentAttempts) START")
if attempts < 10 { // 10회 이하인 경우 에러 방출 후 retry
observer.onError(MyError.error)
attempts += 1
}
observer.onNext(1)
observer.onNext(2)
observer.onCompleted()
return Disposables.create {
print("#\(currentAttempts) END")
}
}
source
.retry(5) // 최대 4회까지만 retry
.subscribe { print($0) }
.disposed(by: bag)
위의 코드는 최종적으로 에러를 방출하며 종료된다.
만약 재시도 요청을 사용자의 버튼 클릭과 같은 인터랙션 감지 시에만 진행하고 싶을때는 retryWhen
연산자를 사용한다.
let trigger = PublishSubject<Void>()
source
.retry(when: { _ in trigger })
.subscribe { print($0) }
.disposed(by: bag)
trigger.onNext(()) // 1회 재시도
트리거 옵저버블을 retry
연산자의 when
클로저에서 리턴해준다. 이후 트리거 옵저버블에서 next
이벤트를 전달하면 소스 옵저버블에서 새로운 구독이 시작된다.
retry
를 통한 재요청은 옵저버블이 리턴되는 형태이므로, 새로운 구독이 시작된다고 표현한다.