본문 바로가기

iOS_RxSwift

RxSwift ErrorTracker GitHub 코드 정리

프로젝트를 하면서 RxSwift 사용시 네트워크 요청에 따른 로딩바와 에러처리에 ActivityIndicator 와 ErrorTracker 를 공통으로 묶어서 유용하게 사용했던 코드를 정리해놓고자 한다.

 

import Foundation
import RxSwift
import RxCocoa

final class ErrorTracker: SharedSequenceConvertibleType {
  typealias SharingStrategy = DriverSharingStrategy
  private let _subject = PublishSubject<CustomedError>()
  /* CustomedError 란 Error를 상속받는 Custom Error Model
     return Single<> 정리글 참조
   */

  func trackError<O: ObservableConvertibleType>(from source: O) -> Observable<O.Element> {
    return source.asObservable().do(onError: onError)
  }

  func asSharedSequence() -> SharedSequence<SharingStrategy, CustomedError> {
    return _subject.asObservable().asDriverOnErrorJustComplete()
  }

  func asObservable() -> Observable<CustomedError> {
    return _subject.asObservable()
  }

  func onError(_ error: Error) {
    if let error = error as? CustomedError {
      _subject.onNext(error)
    }
  }

  deinit {
    _subject.onCompleted()
  }
}

extension ObservableConvertibleType {
  func trackError(_ errorTracker: ErrorTracker) -> Observable<Element> {
    return errorTracker.trackError(from: self)
  }
}

UIViewController 에서 ErrorTracker 를 호출할 경우 연동하여 사용하는 법도 같이 정리해둔다.

BaseViewController 에 대한 내용은 ActivityIndicator 정리 활용

/*
 공통 UIViewController
 */
class CustomViewController: BaseViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    setupRx()
  }
  
  func setupRx() {
  // Way #1.
    errorTracker.asObservable()
      .subscribe(onNext: { [weak self] in
      	print($0.message)
        // self?.openConfirmAlert($0.message)
      }).disposed(by: disposeBag)
      
  // Way #2.
    errorTracker.asObservable()
      .flatMap { [unowned self] in self.openConfirmAlert(msg: $0.message) }
      .subscribe()
      .disposed(by: disposeBag)
  }
  // 등등
}

BaseViewController 를 상속받은 UIViewController 에서는

아래 코드와 같이 trackError 할 경우 공통으로 에러처리가 가능하게 된다.

apiService에서 API 요청에 대한 에러가 났을 경우 CustomedError 모델에 맞는 에러모델로 변환하여 에러를 내려줬을 것이고,

우리가 사용한 errorTracker는 CustomedError에 대해서 ViewController에서 공통처리를 할 수 있다.

 

※ 하나의 ViewController에서 사용자의 이벤트에 따라 여러개의 api 요청을 할 수 있다.

이때 에러를 공통으로 처리할수도 있지만, 어떤 api의 경우 에러에 대해서 custom하게 후속처리를 진행해야하는 경우도  있다.

이때 사용하면 좋은 .catchError 와 Async Model 에 대해서 별도로 정리하겠다.

apiService.exampleLogin() // RxSwift Observable 요청
  .trackActivity(self.activity)  // RIBs 사용하는 경우 presenter.activity
  .trackError(self.errorTracker) // RIBs 사용하는 경우 presenter.errorTracker
  .subscribe(onNext: { [weak self] _ in
  
  }).disposed(by: disposeBag)