RxSwift Traits
- Event를 방출하면 sequence가 종료된다.
- element가 방출되면,
.completed
가 자동으로 방출된다.
- 즉, dispose 된다.
Single
.success(value)
혹은 .error
이벤트만 방출할 수 있다.
Single<Void>.create { single in
single(.success(Void()))
single(.error(CustomError.error))
return Disposables.create()
}
.debug()
.subscribe()
Completable
.completed
혹은 .error
만 방출하며, 값을 방출할 수 없다.
Completable.create { completable in
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)
}
.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)
}
}