-
Rxswift 에러 핸들링 (complete, dispose 대응)개발/Swift 2022. 11. 18. 14:19
네트워크 통신 에러 핸들링에서 필요한 요구사항은 이러하다
- 에러 발생시 Viewcontroller 에서 인지하고 알맞은 에러메시지를 띄운다.
- 에러가 발생해도 원하는 때에 다시 재시도 할수 있어야 한다.
Rx 에서 에러가 발생하면 observable 체인은 dispose되고 이후에 성공이 발생하도 동작 하지 않는다.
일반적인 해결법은 catch가 있으나 catch 또한 complete 로 이벤트가 종료된다.
//VM let productList = PublishSubject<ItemList>() productList.onError(error) productList.onNext(data) ///VC output.productList .catch({ error in self.present(Dialog.getDialog(title: "에러", message: error.localizedDescription), animated: true) return Observable.just([]) }) .bind(to: productListTableView.rx.items(cellIdentifier: "ProductListCell", cellType: ProductListTableViewCell.self)) {[weak self] (_, element, cell) in cell.configure(id: element.id, nameKo: element.nameKo, nameEn: element.nameEn, price: element.price, supplier: element.supplier?.name) self?.loadingView?.removeFromSuperview() } .disposed(by: disposeBag)
위 캐치문에서 에러발생시 처리후 빈배열을 넘겨주었으나
이후 subscription이 완료되어 종료 된다.
만약 재시도를 하고싶으면 어떻게 해야할까?
retry()를 사용하면 에러발생후 다시 subscription 하여 사용한다
하지만 retry를 사용해도 똑같이 complete이 발생하였다.
Observable은 meterialize operator를 제공해준다.
이것을 쓰면 Obsevable<T> → Observable<Event<T>> 가 된다.
즉 결과 값을 Event로 감사고 해당 이벤트안에 에러를 넣어주기 때문에 dispose되지 않고 성공 실패에따른 처리를 따로 해줄수 있다.
let result = output.productList.materilze() result.subscribe{ event in print(event) }
하지만 역시 Complete 이 발생하였다.
1.
만약 Complete이 발생하지않고 지속적인 구독을 위해서는
구독하고 있는 Observable에 onError를 넣어주면 안되었다.
onNext를 통해 에러를 전달 해주면 해결이 가능하다.
그러려면
구독하고있는 이벤트 자체가 Event<T> 형태여야한다.
//VM let productList = PublishSubject<Event<ItemList>>() productList.onNext(.error(error)) productList.onNext(.next(data)) ///VC output.productList .map({ event -> [ItemList] in switch event { case .error: if let errorMessage = event.error?.localizedDescription { self.present(Dialog.getDialog(title: "에러", message: errorMessage), animated: true) } return [] default: if let data = event.element{ return data } return [] } }) .bind(to: productListTableView.rx.items(cellIdentifier: "ProductListCell", cellType: ProductListTableViewCell.self)) {[weak self] (_, element, cell) in cell.configure(id: element.id, nameKo: element.nameKo, nameEn: element.nameEn, price: element.price, supplier: element.supplier?.name) self?.loadingView?.removeFromSuperview() } .disposed(by: disposeBag)
결국 구독하는 스트림에 onError를 직접 넣어주면 어느 방법을 써도 다시 사용할수 없다.
2.
아니면 별개의 error output을 만들어 VC 에서 사용하는 방법이 있다.
//VM let productList = PublishSubject<ItemList>() let error = PublishSubject<Error>() productList.onNext(data) error.onNext(error)
'개발 > Swift' 카테고리의 다른 글
DispatchQueue 에서 주의할 데드락 현상 (0) 2022.11.21 Rxswift - ObserveOn , SubscribeOn (0) 2022.11.18 [Combine] - 1. publisher & subscriber (0) 2022.11.13 Rxswift operators - flatmap, flatmapLatest, merge (0) 2022.11.11 Combine Vs RxSwift (0) 2022.11.09