관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] RxSwift, RxSwiftExt, RxOptional 많이 쓰는 연산자 정리 본문

iOS 응용 (swift)

[iOS - swift] RxSwift, RxSwiftExt, RxOptional 많이 쓰는 연산자 정리

jake-kim 2021. 12. 21. 22:44

RxSwift

  • withUnretained(self) - capture list를 사용하지 않고 심플하게 표현
  • Observable.of(1, 2, 3, 4, 5) .withUnretained(self) .subscribe { vc, value in vc.temp = value } .disposed(by: disposeBag)​

1) Combine(결합) 연산자

  • (merge, combineLatest, withLatestFrom, zip, concat) - 이전 글 참고
  • Scan
    Observable.of(1,2,3,4)
      .scan(0, accumulator: { (prevValue, newValue) in
        return prevValue + newValue
      })
      .do { print($0) }
      .subscribe()
    // 1
    // 3
    // 6
    // 10
  • Reduce
    Observable.of(1,2,3,4,5)
      .reduce(0, accumulator: +)
      .subscribe(onNext: { print($0) })
      .disposed(by: disposeBag)
    
    // 1
    // 3
    // 6
    // 10
    // 15​

2) Transform 연산자

  • map
Observable.of(1,2,3,4,5)
  .map { $0 + 1 }
  .subscribe { print($0) }
  .disposed(by: disposeBag)
// next(2)
// next(3)
// next(4)
// next(5)
// next(6)
// completed
  • flatmap - 구독하고 있는 sequence와는 다른 sequence를 리턴할 때 사용
let sequenceInt = Observable.of(1,2,3)
let sequenceString = Observable.of("A","B","C")

sequenceInt
  .flatMap { (x: Int) -> Observable<String> in
    print("\(x)")
    return sequenceString
  }
  .subscribe { print($0) }
  .disposed(by: disposeBag)


// 1
// next(A)
// 2
// next(B)
// next(A)
// 3
// next(C)
// next(B)
// next(A)
// next(C)
// next(B)
// next(C)
// completed
  • flatMapFirst - 클로저에 해당하는 sequence가 끝날때까지 기다렸다가 방출
    let timer = Observable<Int>
      .interval(.seconds(2), scheduler: MainScheduler.instance)
      .take(4)
    
    timer.flatMapFirst { (seconds: Int) -> Observable<Int> in
      let newTimer = Observable<Int>
        .interval(.seconds(1), scheduler: MainScheduler.instance)
        .take(4)
        .map { _ in seconds + 100 }
      return newTimer
    }
    .subscribe { print($0) }
    .disposed(by: disposeBag)​
    
    // next(100)
    // next(100)
    // next(100)
    // next(100)
    // next(103)
    // next(103)
    // next(103)
    // next(103)
    // completed
  • flatMapLatest
    • flatMapFirst는 이전 sequence를 무시하지 않지만, flatMapLatest는 무시
    • 마지막 sequnece만 observing
persons.asObservable()
    .flatMapLatest { $0.score.asObservable() }
    .subscribe(onNext: {
        print($0)
    }).disposed(by: disposeBag)

persons.onNext(jake)
john.score.accept(100)

persons.onNext(jane)
mary.score.accept(80)

john.score.accept(40) // <- 새로운 sequence에 집중하므로 무시

//75
//100
//95
//80

3) Filtering 연산자

  • distinctUntilChnaged - 연달아 중복된 값이 올때 무시
    Observable.of(1, 2, 2, 1, 3)
       .distinctUntilChanged()
       .subscribe(onNext: {
           print($0)
       })
       .disposed(by: disposeBag)
    
    /* Prints :
     1
     2
     1
     3
    /*​
  • filter
    Observable.of(1,2,3,4,5,6)
      .filter { $0 % 2 == 0 }
      .subscribe { print($0) }
      .disposed(by: disposeBag)
    // next(2)
    // next(4)
    // next(6)
    // completed​

4) 시간 연산자

Error Handling

RxOptional

  • cocoapods
    pod 'RxOptional'​
  • filterNill
    // filterNill
    Observable<String?>
      .of("1", nil, "3")
      .filterNil()
      .subscribe { print($0) }
      .disposed(by: disposeBag)
    
    // next(1)
    // next(3)
    // completed​
  • replaceNilWith
    Observable<String?>
      .of("1", nil, "3")
      .replaceNilWith("2")
      .subscribe { print($0) }
      .disposed(by: disposeBag)
    
    // next(1)
    // next(2)
    // next(3)​

* 참고

- RxOptional: https://github.com/RxSwiftCommunity/RxOptional

- error handling: https://github.com/fimuxd/RxSwift/blob/master/Lectures/14_Error%20Handling%20in%20Practice/Ch.14%20Error%20Handling%20in%20Practice.md

 

RxSwiftExt

  • cocoapods
    pod 'RxSwiftExt'​
  • distinct() 중복 값 제외
    Observable.of("1", "2", "3", "1")
      .distinct()
      .toArray()
      .subscribe { print($0) }
      .disposed(by: disposeBag)
      
    // success(["1", "2", "3"])​
  • retry - error or complte 이벤트가 발생한 경우 sequence를 재생성
    • immediate(maxCount:): error가 발생한 경우, 최대 maxCount번 까지 재구독
    • delay(maxCount:time:): 지연 시간이 주어지고 + 최대 maxCount번 까지 재구독
    • exponentialDelayed(maxCount:initial:multiplier:): 재시도마다 지연 시간에 multiplier가 곱해지는 것
    • customTimerDelayed(maxCount:delayCalculator: (uInt) -> Double) : 재구독이 지연되어야 하는 시간을 클로저로 제공
      let url = URL(string: "https://ios-development.tistory.com/")!
      let request = URLRequest(url: url)
      _ = URLSession.shared.rx.response(request: request)
        .map { response in
          print(response)
        }
        .retry(.exponentialDelayed(maxCount: 3, initial: 1.0, multiplier: 3.0))
        
        // 3회 반복, 1초간 지연, *3초씩 늘어남​

cf) retry를 이용한 서버 에러처리: 이전 글 참고

Comments