본문 바로가기
RxSwift

[RxSwift] Error Handling

by thoonk: 2024. 3. 8.
반응형

RxSwift에서 에러 핸들링에 관한 내용을 기록합니다.

RxSwift에서의 에러 관리

Catch

error 를 새로운 Observable 또는 값으로 처리

catch(_ handler:)

  • 클로저를 매개변수로 받아 완전히 다른 형태의 observable로 변환
public func `catch`(_ handler: @escaping (Swift.Error) throws -> PrimitiveSequence<Trait, Element>)
    -> PrimitiveSequence<Trait, Element> {
    PrimitiveSequence(raw: self.source.catch { try handler($0).asObservable() })
}
  • 예시
func getUser(id: Int) -> Observable<User> {
  return network.getUser(id)
    .catchError { error in
      if let apiError = error as? APIError {
        switch apiError.code {
        case 404:
          return Observable.empty() 
        case 401:
          return Observable.error(AuthenticationError()) 
        default:
          return Observable.error(error) 
        }
      } else {
        return Observable.error(error)
      }
    }
}

catchAndReturn(_ element:)

  • 에러를 무시하고 이전에 선언해둔 값을 반환함.
  • catch 에 비해 제한적, 주어진 타입의 에러에 대한 값을 반환할 수 없음. → 모든 에러에 대한 동일한 값이 반환됨.
public func catchAndReturn(_ element: Element)
    -> PrimitiveSequence<Trait, Element> {
    PrimitiveSequence(raw: self.primitiveSequence.source.catchAndReturn(element))
}

Retry

에러 상황에서 제한적 또는 무제한으로 재시도하기

retry 연산자가 observable 에러에서 사용되면 observable 내 전체 작업을 반복한다는 것을 의미

retry(_ maxAttemptCunt:)

  • 재시도를 설정하지 않으면 무제한, 횟수로 설정할 수 있음.
public func retry(_ maxAttemptCount: Int)
		-> PrimitiveSequence<Trait, Element> {
		PrimitiveSequence(raw: self.source.retry(maxAttemptCount))
}
  • 예시
func getUser(id: Int) -> Observable<User> {
  return network.getUser(id)
		.retry(3)
    .catchError { error in
      if let apiError = error as? APIError {
        switch apiError.code {
        case 404:
          return Observable.empty() 
        case 401:
          return Observable.error(AuthenticationError()) 
        default:
          return Observable.error(error) 
        }
      } else {
        return Observable.error(error) 
      }
    }
}

retry(when notificationHandler:)

  • notificationHandler 는 TriggerObservable 타입이므로 Observable 또는 Subject 모두 될 수 있음.
  • 또한, 임의적으로 retry 를 trigger 하는데 사용됨.
public func retry<TriggerObservable: ObservableType>(when notificationHandler: @escaping (Observable<Swift.Error>) -> TriggerObservable)
    -> PrimitiveSequence<Trait, Element> {
    PrimitiveSequence(raw: self.source.retry(when: notificationHandler))
}
  • 네트워크 연결 상태에 따른 데이터 요청 재시도
let networkReachabilityObservable = Observable<Bool>.create { observer in
  // 네트워크 연결 상태 변화 관찰
  
  if isNetworkReachable {
    observer.onNext(true)
  } else {
    observer.onNext(false)
  }
}

let observable = Observable<Data> { observer in
  // 네트워크 요청 수행
  
  if !isNetworkReachable {
    observer.onError(NetworkError())
  } else {
    // ...
  }
}

observable
  .retry(when: networkReachabilityObservable.filter { $0 }) // 네트워크 연결 활성화 시 재시도
  .subscribe(
    onNext: { data in
      // 데이터 처리
    },
    onError: { error in
      // 네트워크 연결 오류 처리
    }
  )

Materialize/dematerialize

  • Observable 을 Observable<Event>로 변환
  • 실패한 시퀀스를 디버깅할 수 있음.
  • 외부 시퀀스를 종료하지 않으면서 에러를 처리할 때 유용함.
public func materialize() -> Observable<Event<Element>> {
    Materialize(source: self.asObservable())
}
  • 예시
trigger
    .flatMapLatest {
        return dataSource.fetchItems()
            .materialize()
    }
    .subscribe(with: self, onNext: { owner, event in
        switch event {
        case .next(let items):
            print(items)
        case .error(let error):
            // error 처리
        case .completed:
            break
        }
    })
    .disposed(by: disposeBag)
  • 커스텀 이벤트 로그
 observableToLog.materialize() 
 	.do(onNext: { (event) in 
 		myAdvancedLogEvent(event)
 	})
 	.dematerialize()

 

부족한 점 피드백해주시면 감사합니다 :)

Ref.

https://github.com/fimuxd/RxSwift/blob/master/Lectures/14_Error Handling in Practice/Ch.14 Error Handling in Practice.md

반응형

'RxSwift' 카테고리의 다른 글

[RxSwift] Traits Part 2.  (2) 2024.03.08
[RxSwift] Traits Part 1.  (0) 2024.03.08
[RxSwift] Time Based Operators  (0) 2022.07.18
[RxSwift] Extension Reactive  (0) 2022.07.14
[RxSwift] Combining Operators  (0) 2022.05.26

댓글