-
[RxSwift] Error Handling [2]iOS/RxSwift 2022. 1. 27. 01:40
이전 글에서 Error Handling에 대해서 탐구하는 과정을 기록했다.
그 이후 여러가지 Demo나 Article을 읽으며 어떤 방식이 더 좋은 선택일지 고민했다.
수 개의 프로젝트를 살펴보았을 때, 대게 몇가지 패턴으로 에러를 처리하고 있었다.
그 중, 나는
materialize
를 활용한 방식에 주목했다.일단 이 방식이 입증된 방식인지를 알기 위해서 해당 키워드에 대한 수많은 검색을 통해서 저명한 개발자들의 활용사례를 발견할 수 있었다.
Materialize
일단 구현부를 보면, Observable자체가 다른 Observable의 source로 변환해주는 동작임을 알 수 있다.
Marble Diagram을 보면 더 확실하게 알 수 있다.
onNext(1)
->onNext(onNext(1))
onNext(2)
->onNext(onNext(2))
onCompleted
->onNext(onCompleted)
이런식으로 변환이 된다. 따라서 모든 이벤트가 onNext가 되는 것이므로 스트림이 종료 되지 않는다.
함께 활용되는 것들의 키워드는 다음과 같다.
RxSwift.Event :
element
,error
RxSwiftExt :elements
,errors
활용
Materialize
를 활용해서 Error Handling을 하는 이유는, 아마 대게 네트워크 통신시 발생한 에러가propagate down the chain
(Article에서 나온 표현)해서 모든 subscription을 종료시키는것을 방지하기 위해서다.Network에서 자주 사용되는 Trait에는 Single이 있다. 하지만 Single에 곧바로 materialize를 적용할 수 없다.
사실 왜 안되는지 이해가 안가지만 Add materialize and dematerialize for Single 이 discussion에서 운영진을의 판단을 직접 들을 수 있다.
아무튼, Observable과 materialize를 활용한 예제는 아래와 같다.
// 출처 : https://michaellong.medium.com/rxswift-better-error-handling-with-compactmap-48a5d314d0f1 class CompactMapOperationViewModel { var data: Observable<[String]>! var error: Observable<String?>! var dataService = DataService() init(load: Observable<Void>) { let loading = load .flatMapLatest { [unowned self] _ in self.dataService.load().materialize() } .share() data = loading .compactMap { $0.element?.map { "Hello, \($0)" } .observeOn(MainScheduler.instance) error = loading .map { $0.error?.localizedDescription } .observeOn(MainScheduler.instance) }
이 예제를
SwiftExt
에 있는elements
,errors
operator로 대체하면 아래와 같다.import RxswiftExt ... let loading = load .flatMapLatest { [unowned self] _ in self.dataService.load().materialize() } .share() data = loading .elements() .observeOn(MainScheduler.instance) error = loading .errors() .observeOn(MainScheduler.instance)
결국 똑같은거라서 깔끔한 코드를 원하면 Ext를 추가해서 아래 방식을, 적은 라이브러리를 원하면 위의 방식을 사용하면 된다.
참고로 Single에 적용하고 싶다면 single.asObservable().materialize()를 사용하면 된다.
'iOS > RxSwift' 카테고리의 다른 글
[RxSwift6] "withUnretained" operator로 리펙토링하기 (0) 2022.02.02 [RxSwift] weak, unowned self에 대한 의문 (0) 2022.01.27 [RxSwift] Error Handling [1] (0) 2022.01.25 RxSwift로 리펙토링 맛보기 (0) 2022.01.03 [Rxswift] 03.Subjects (0) 2021.12.19