반응형
OnError 로 처리하면 되지 않낭?
- Error 이벤트는 Observable 을 종료시키게 된다. 그래서 종료시키지 않고 다음과 같이 이벤트를 발생키시고 completed 가 발생되도록 error handling 을 하고자 하는 것이당!
RxSwift 에서는 보통 세가지 방법으로 Error Handling 을 할 수 있다.
- catch : 특정 값으로 Error 복구
- retry : 재시도 하기
- materialize / dematerialize : Sequence 를 제어해서 처리
Catch
- Catch연산자는 Next와 Completed 연산자는 그대로 방출한다.
- API 요청 코드에서 Catch가 많이 사용된다.
- Error이벤트가 전달되면 새로운 Observable을 전달한다.
- 네트워크 에러가 있을 경우, UI가 업데이트가 안된다 -> Observable에 기본값이 로컬캐시값을 담아서UI업데이트 하는 형식으로 사용한다
enum TestError: Int, Error {
case notFound = 200
case noInternet = -1
}
let observable = Observable<Int>
.create { observer -> Disposable in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onError(TestError.notFound)
observer.onError(TestError.noInternet)
return Disposables.create { }
}
observable
.catch { err -> Observable<Int> in
let testError = err as? TestError
return .just(testError?.rawValue ?? -1)
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
/*
1
2
3
200
*/
CatchErrorJustReturn
- 에러를 만다면, 파라미터 값을 그대로 방출한다.
- 주로 에러발생 시, 기본값 혹은 로컬 캐시값을 방출할 때 쓰인다.
let subject = PublishSubject<Int>()
subject
.catchAndReturn(0)
.subscribe { print($0) }
.disposed(by: disposeBag)
subject.onError(MyError.error) // next(0)
Retry
- 소스 Observable에서 에러 발생시, Observable에 대한 구독을 해체하고 새로운 Observable에 구독을 실행한다.
- 새로운 구독이 시작되기 때문에, Observable의 모든작업이 다시 시작된다.
- 에러가 발생하지 않으면, 정상적으로 종료되고, 에러가 발생하면 또 다시 새로운 구독을 실행한다.
- 파라미터에 횟수를 지정할 수 있지만 + 1해야한다. 즉 3으로 설정할 경우, 2번만 retry하게 된다.
var attemptCount = 1
let source = Observable<Int>.create { observer in
let currentAttemptCount = attemptCount
print("#START => \(currentAttemptCount)")
// 2번째 시도까지 에러 방출.
if attemptCount < 3 {
observer.onError(MyError.myError)
attemptCount += 1
}
observer.onNext(1)
observer.onCompleted()
return Disposables.create {
print("#END => \(currentAttemptCount)")
}
}
source
// 최대 4번의 재시도.
.retry(5)
.subscribe {
print($0)
}
.disposed(by: disposeBag)
/*
#START => 1
#END => 1
// Error 이벤트가 방출되었기 때문에 재시도.
#START => 2
#END => 2
// Error 이벤트가 방출되었기 때문에 재시도.
#START => 3
next(1)
completed
#END => 3
*/
// maxAttemptCount 보다 많이 시도할 경우에는? Error 이벤트를 방출한다.
// 다음과 같이 작성하면 maxAttemptCount 가 넘었기 때문에 재시도 할 수 없다.
source
// 최초 1번 시도.
.retry(1)
.subscribe(onNext: {
print($0)
}, onError: {
print("error: \($0)")
})
.disposed(by: disposeBag)
/*
#START => 1
#END => 1
error: myError
*/
Retry(When:)
- Error가 떨어졌을 때 error를 가공해 observerbleType을 반환한다.
- 즉 다음 예제처럼 retry시점을 조작하거나 값을 변경할 수 있다.
- closure를 파라미터로 받아서 해당 해당 closure가 완료되면 시도했던 로직 self로 다시 sequence로 만들어서 동작
- subscribe()하기 전에 사용하고, retry(when:)의 클로저 내부에서 error.flatMap {}을 사용
- Observable<Int>.timer를 통해서 언제 재시도를 할건지 정의
- retry(when:) 다음 스트림에 take(3)을 넣어서 얼마만큼 반복할건지 명시
API.getName()
.retry(when: { error in
error.flatMap { _ in
Observable<Int>
.timer(.seconds(3), period: nil, scheduler: MainScheduler.asyncInstance)
}
})
.take(3)
.subscribe()
.disposed(by: self.disposeBag)
반응형
'iOS > RxSwift' 카테고리의 다른 글
[RxSwift] ActivityIndicatorView를 Rx로 쉽게 컨트롤하기 (0) | 2024.06.08 |
---|---|
[RxSwift] RxCocoa (binding, Traits, Driver..등) (0) | 2023.11.04 |
[RxSwift] Create Operators [2] (0) | 2023.10.30 |
[RxSwift] Create Operators [1] (0) | 2023.10.29 |
[RxSwift] Relay (1) | 2023.10.29 |