[RxSwift] Error Handling Operator
Network Error Handling์ ๋ํด ์์๋ณด๋ค๊ฐ ๊ด๋ จ operator๋ค์ ์ ๋ฆฌํด๋ณด๋ ค๊ตฌ ํฉ๋๋ค.
์ฐธ๊ณ : https://okanghoon.medium.com/rxswift-5-error-handling-example-9f15176d11fc
RxSwift #5โ—โError Handling & Example
์ด๋ฒ์๋ RxSwift์์ ์ด๋ป๊ฒ Error Handling ์ ํ๋์ง ์ฑ์์ ํํ ๋ฐ์ํ๋ ์๋ฌ ์์ ๋ค์ ํตํด ์์๋ณด๋ ค๊ณ ํ๋ค.
okanghoon.medium.com
RxSwift์์๋ Error Handling์ ํ๋๋ฐ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
1. Catch ํน์ ๊ฐ์ผ๋ก error ๋ณต๊ตฌ
2. Retry ์ฌ์๋
3. materialize / dematerialize : Sequence ๋ฅผ ์ ์ดํด์ ์ฒ๋ฆฌ
1. Catch
Error ๋ฐ์ ์, catch ๋ด์ ํน์ ๊ฐ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๊ณ complete ์ํจ๋ค.
1) catchError
let observable = Observable<Int>
.create { observer -> Disposable in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onError(NSError(domain: "", code: 100, userInfo: nil))
observer.onError(NSError(domain: "", code: 200, userInfo: nil))
return Disposables.create { }
}
observable
.catchError { .just(($0 as NSError).code) }
.subscribe { print($0) }
.disposed(by: disposeBag)
/* Prints:
next(1)
next(2)
next(3)
next(100)
completed
*/
1, 2, 3์ ์ถ๋ ฅ ํ์ code 100 error๊ฐ ๋ฐ์ํ๊ณ catchError์์ Error๊ฐ .just(100)์ผ๋ก ๋ฐ๋์ด ์ถ๋ ฅ๋๊ณ complete๋๋ค.
2) catchErrorJustReturn
let observable = Observable<Int>
.create { observer -> Disposable in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onError(NSError(domain: "", code: 100, userInfo: nil))
observer.onError(NSError(domain: "", code: 200, userInfo: nil))
return Disposables.create { }
}
observable
.catchErrorJustReturn(999)
.subscribe { print($0) }
.disposed(by: disposeBag)
/* Prints:
next(1)
next(2)
next(3)
next(999)
completed
*/
error๊ฐ ๋ฐ์ํ์๋ Error๋ฅผ ๋ฌด์ํ๊ณ ์ง์ ํ element๋ฅผ ๋ฐํํ๋ค.
2. retry
source observable์์ error๊ฐ ๋ฐ์์ ๋ค์ subscribeํ์ฌ error๊ฐ ๋ฐ์ํ์ง ์๊ธธ ๋ฐ๋๋ค. ๋ผ๊ณ ์๊ฐํ๊ณ ์๋ค.
1) retry()
์ฐ์ฐ์ ์ฑ๊ณตํ ๋๊น์ง ๊ณ์ ๋ฐ๋ณตํ๋ค.
let reloadPublisher = PublishSubject<Void>()
reloadPublisher
.flatMap {
Api.getRepositories()
.retry()
}
์ธํฐ๋ท ์ฐ๊ฒฐ์ ๋๊ณ Api๊ฐ ์คํจํ๊ฒ ๋๋ฉด ๊ณ์ Api.getRepositories()์ ํธ์ถ ํ ๊ฒ์ด๋ค.
2) retry(count)
๋ฐ๋ณต ํธ์ถํ count๋ฅผ ์ง์ ํ๋ค.
let reloadPublisher = PublishSubject<Void>()
reloadPublisher
.flatMap {
Api.getRepositories()
.retry(3)
}
let observable = Observable<Int>
.create { observer -> Disposable in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onError(NSError(domain: "", code: 100, userInfo: nil))
observer.onError(NSError(domain: "", code: 200, userInfo: nil))
return Disposables.create { }
}
observable
.retry(2)
.subscribe { print($0) }
.disposed(by: disposeBag)
/* Prints:
next(1)
next(2)
next(3)
next(1)
next(2)
next(3)
error(Error Domain= Code=100 "(null)")
*/
์ฌ์๋ ํ์๋ฅผ ๋์ด์๋ฉด error๋ฅผ ๋ฐฉ์ถํ๋ค.
3) retryWhen()
์ฌ์๋ ํ๋ ์์ ์ ์ง์ ํ ์ ์๊ณ , ํ๋ฒ๋ง ์ํํ๋ค.
retry ์ ๋ค๋ฅด๊ฒ ๋ง์ง๋ง Error๋ฅผ ์ด๋ฒคํธ๋ก ์ ๋ฌํ์ง ์๋๋ค.
let observable = Observable<Int>
.create { observer -> Disposable in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onError(NSError(domain: "", code: 100, userInfo: nil))
observer.onError(NSError(domain: "", code: 200, userInfo: nil))
return Disposables.create { }
}
observable
.retryWhen { err -> Observable<Int> in
return .timer(3, scheduler: MainScheduler.instance)
}
.subscribe { print($0) }
.disposed(by: disposeBag)
/* Prints:
next(1)
next(2)
next(3)
(3 seconds)
next(1)
next(2)
next(3)
completed
*/
3. Materialize / Dematerialize
- RxSwift ์์ ์ฐ์ด๋ Event Sequence๋ฅผ ์ ์ดํ ์ ์๊ฒ ํด์ค๋ค.
- ๋ณดํต Materialize / Dematerialize ๋ ํจ๊ป ์ฌ์ฉํ๋ค.
- Observable์ ๋ถํดํ ์ ์๊ธฐ ๋๋ฌธ์ ์ ์คํ๊ฒ ์ฌ์ฉํด์ผ ํ๋ค.
Materialize
- Sequence ๋ฅผ Event<Element> Sequence๋ก ๋ณํํ๋ค.
Dematerialize
- Event<Element> Sequence ๋ฅผ ๋ค์ Sequence๋ก ๋ณํํ๋ค.
let observable = Observable<Int>
.create { observer -> Disposable in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onError(NSError(domain: "", code: 100, userInfo: nil))
observer.onError(NSError(domain: "", code: 200, userInfo: nil))
return Disposables.create { }
}
observable
.materialize()
.map { event -> Event<Int> in
switch event {
case .error:
return .next(999)
default:
return event
}
}
.dematerialize()
.subscribe { event in
print(event)
}
.disposed(by: disposeBag)
/* Prints
next(1)
next(2)
next(3)
next(999)
completed
*/