[RxSwift] 3.Traits

DEV-YONG·2022년 1월 9일
0

RxSwift

목록 보기
3/8

RxSwift Traits

  • Event를 방출하면 sequence가 종료된다.
    • element가 방출되면, .completed가 자동으로 방출된다.
    • 즉, dispose 된다.

Single

  • .success(value) 혹은 .error 이벤트만 방출할 수 있다.
Single<Void>.create { single in

    single(.success(Void()))
    single(.error(CustomError.error))
//      single(.completed) ❌
    return Disposables.create()
}
.debug()
.subscribe()

Completable

  • .completed 혹은 .error만 방출하며, 값을 방출할 수 없다.
Completable.create { completable in

//      completable(.success) ❌
    completable(.error(CustomError.error))
    completable(.completed)

    return Disposables.create()
}
.debug()
.subscribe()
}

Maybe

  • success(value) 혹은 .completed 혹은 .error 를 방출한다.
Maybe<Void>.create { maybe in

    maybe(.success(Void()))
    maybe(.error(CustomError.error))
    maybe(.completed)

    return Disposables.create()
}
.debug()
.subscribe()

RxCocoa Traits

Driver

  • .error를 방출하지 않는다.
  • Observe가 Main scheduler에서 일어난다.
  • Side Effect를 공유한다. (.share(replay: 1, scope: .whileConnected))
typealias Driver<Element> = SharedSequence<DriverSharingStrategy, Element>
  • 의도된 UseCase는 어플리케이션을 Drive하는 시퀀스를 모델링한다.
    • CoreData 모델로부터 UI를 drive한다.
    • 다른 UI 요소(binding)의 값을 사용하여 UI를 drive한다.
[AS-IS]
fetchResult(query)
   .observeOn(MainScheduler.instance)
   .catchErrorJustReturn([])
   .share(replay: 1)
[TO-BE]
fetchResult(query)
   .asDriver(onErrorJustReturn: [])
func fetchAutoCompleteItems(_ query: String?) -> Observable<[String]> {
    return .empty()
}

let resultTextField = UITextField()
let queryTextField = UITextField()

//  let results = queryTextField.rx.text
//      .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
//      .flatMapLatest { query in
//          fetchAutoCompleteItems(query)
//      }
//
//  let results = queryTextField.rx.text
//      .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
//      .flatMapLatest { query in
//          fetchAutoCompleteItems(query)
//              .observeOn(MainScheduler.instance)
//              .catchErrorJustReturn([])
//      }
//      .share(replay: 1)

let results = queryTextField.rx.text
    .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
    .flatMapLatest { query in
        fetchAutoCompleteItems(query)
    }
    .asDriver(onErrorJustReturn: [])

results.map { "\($0.count)" }
    .drive(resultTextField.rx.text)
    .disposed(by: disposeBag)

ControlProperty / ControlEvent

ControlProperty

  • UI Element의 property를 나타내기 위한 Trait이다.
  • 실패하지 않는다.
  • share(replay: 1) 처럼 행위를 한다.
    • Stateful하다.
    • Subscription(즉, subscribe 호출) 시 마지막 요소가 생성된 경우 즉시 재생된다.
    • Subscriber에게 구독 즉시 초치값을 전송한다.
  • base가 deallocated될 때 complete된다.
  • Main scheduler에서 subscribe되는 것이 보장된다. (subscribeOn(ConcurrentMainScheduler.instance))
    • MainScheduler.instance 에서 event가 전달된다.
extension Reactive where Base: UISearchBar {

    var value: ControlProperty<String?> {
        let source = Observable<String?>.deferred { [weak base] () -> Observable<String?> in
            guard let base = base else { return .empty() }
            let text = base.text
            return base.rx.delegate
                .methodInvoked(#selector(UISearchBarDelegate.searchBar(_:textDidChange:)))
                .map { return $0[1] as? String }
                .startWith(text)
        }
        let bindingObserver = Binder(self.base) { (searchBar, text: String?) in
            searchBar.text = text
        }
        return ControlProperty(values: source, valueSink: bindingObserver)
    }

}

extension Reactive where Base: UISegmentedControl {

    var selectedSegmentIndex: ControlProperty<Int> {
        base.rx.controlProperty(
            editingEvents: [.allEditingEvents, .valueChanged],
            getter: {
                $0.selectedSegmentIndex
            },
            setter: {
                $0.selectedSegmentIndex = $1
            }
        )
    }

}

ControlEvent

  • 절대 실패하지 않는다.
  • Subscriber에게 초긱밧을 전송하지 않는다.
  • base가 deallocated될 때 complete된다.
  • Main scheduler에서 subscribe되는 것이 보장된다. (subscribeOn(ConcurrentMainScheduler.instance))
    • MainScheduler.instance 에서 event가 전달된다.
extension Reactive where Base: UICollectionView {

    var itemSelected: ControlEvent<IndexPath> {
        let source = delegate.methodInvoked(#selector(UICollectionViewDelegate.collectionView(_:didSelectItemAt:)))
            .map { a in
                return a[1] as! IndexPath
            }

        return ControlEvent(events: source)
    }
}
profile
🧑🏻‍💻 iOS Developer @TOSS

0개의 댓글