Observer - 观察者
AnyObserver
AnyObserver
可以用来描叙任意一种观察者。
例如:
打印网络请求结果:
1 2 3 4 5 6 7
| URLSession.shared.rx.data(request: URLRequest(url: url)) .subscribe(onNext: { data in print("Data Task Success with count: \(data.count)") }, onError: { error in print("Data Task Error: \(error)") }) .disposed(by: disposeBag)
|
可以看作是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let observer: AnyObserver<Data> = AnyObserver { (event) in switch event { case .next(let data): print("Data Task Success with count: \(data.count)") case .error(let error): print("Data Task Error: \(error)") default: break } }
URLSession.shared.rx.data(request: URLRequest(url: url)) .subscribe(observer) .disposed(by: disposeBag)
|
用户名提示语是否隐藏:
1 2 3
| usernameValid .bind(to: usernameValidOutlet.rx.isHidden) .disposed(by: disposeBag)
|
可以看做是:
1 2 3 4 5 6 7 8 9 10 11 12
| let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in switch event { case .next(let isHidden): self?.usernameValidOutlet.isHidden = isHidden default: break } }
usernameValid .bind(to: observer) .disposed(by: disposeBag)
|
Binder
Binder
主要有以下两个特征:
- 不会处理错误事件
- 确保绑定都是在给定
Scheduler
上执行(默认 MainScheduler
)
一旦产生错误事件,在调试环境下将执行 fatalError
,在发布环境下将打印错误信息。
在 AnyObserver
时,我们举了一个这样的例子:
1 2 3 4 5 6 7 8 9 10 11 12
| let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in switch event { case .next(let isHidden): self?.usernameValidOutlet.isHidden = isHidden default: break } }
usernameValid .bind(to: observer) .disposed(by: disposeBag)
|
由于这个观察者是一个 UI 观察者,所以它在响应事件时,只会处理 next
事件,并且更新 UI
的操作需要在主线程上执行。
因此一个更好的方案就是使用 Binder
:
1 2 3 4 5 6 7
| let observer: Binder<Bool> = Binder(usernameValidOutlet) { (view, isHidden) in view.isHidden = isHidden }
usernameValid .bind(to: observer) .disposed(by: disposeBag)
|
复用
由于页面是否隐藏是一个常用的观察者,所以应该让所有的 UIView
都提供这种观察者:
1 2 3 4 5 6 7 8 9 10 11
| extension Reactive where Base: UIView { public var isHidden: Binder<Bool> { return Binder(self.base) { view, hidden in view.isHidden = hidden } } }
usernameValid .bind(to: usernameValidOutlet.rx.isHidden) .disposed(by: disposeBag)
|
这样你不必为每个 UI 控件单独创建该观察者。这就是 usernameValidOutlet.rx.isHidden
的由来,许多 UI
观察者 都是这样创建的:
- 按钮是否可点击
button.rx.isEnabled
1 2 3 4 5 6 7
| extension Reactive where Base: UIControl { public var isEnabled: Binder<Bool> { return Binder(self.base) { control, value in control.isEnabled = value } } }
|
label
的当前文本 label.rx.text
1 2 3 4 5 6 7
| extension Reactive where Base: UILabel { public var text: Binder<String?> { return Binder(self.base) { label, text in label.text = text } } }
|
Observable & Observer 既是可被监听的序列也是观察者
在我们所遇到的事物中,有一部分非常特别。它们既是可被监听的序列也是观察者。
AsyncSubject
AsyncSubject
将在源 Observable
产生完成事件后,发出最后一个元素(仅仅只有最后一个元素),如果源 Observable
没有发出任何元素,只有一个完成事件。那 AsyncSubject
也只有一个完成事件。
它会对随后的观察者发出最终元素。如果源 Observable
因为产生了一个 error
事件而中止, AsyncSubject
就不会发出任何元素,而是将这个 error
事件发送出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let disposeBag = DisposeBag() let subject = AsyncSubject<String>()
subject .subscribe { print("Subscription: 1 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🐶") subject.onNext("🐱") subject.onNext("🐹") subject.onCompleted()
|
PublishSubject
PublishSubject
将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者。如果你希望观察者接收到所有的元素,你可以通过使用 Observable
的 create
方法来创建 Observable
,或者使用 ReplaySubject
。
如果源 Observable
因为产生了一个 error
事件而中止, PublishSubject
就不会发出任何元素,而是将这个 error
事件发送出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| let disposeBag = DisposeBag() let subject = PublishSubject<String>()
subject .subscribe { print("Subscription: 1 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🐶") subject.onNext("🐱")
subject .subscribe { print("Subscription: 2 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🅰️") subject.onNext("🅱️")
|
ReplaySubject
ReplaySubject
将对观察者发送全部的元素,无论观察者是何时进行订阅的。
这里存在多个版本的 ReplaySubject
,有的只会将最新的 n
个元素发送给观察者,有的只会将限制时间段内最新的元素发送给观察者。
如果把 ReplaySubject
当作观察者来使用,注意不要在多个线程调用 onNext
, onError
或 onCompleted
。这样会导致无序调用,将造成意想不到的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| let disposeBag = DisposeBag() let subject = ReplaySubject<String>.create(bufferSize: 1)
subject .subscribe { print("Subscription: 1 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🐶") subject.onNext("🐱")
subject .subscribe { print("Subscription: 2 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🅰️") subject.onNext("🅱️")
|
BehaviorSubject
当观察者对 BehaviorSubject
进行订阅时,它会将源 Observable
中最新的元素发送出来(如果不存在最新的元素,就发出默认元素)。然后将随后产生的元素发送出来。
如果源 Observable
因为产生了一个 error
事件而中止, BehaviorSubject
就不会发出任何元素,而是将这个 error
事件发送出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| let disposeBag = DisposeBag() let subject = BehaviorSubject(value: "🔴")
subject .subscribe { print("Subscription: 1 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🐶") subject.onNext("🐱")
subject .subscribe { print("Subscription: 2 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🅰️") subject.onNext("🅱️")
subject .subscribe { print("Subscription: 3 Event:", $0) } .disposed(by: disposeBag)
subject.onNext("🍐") subject.onNext("🍊")
|
ControlProperty
ControlProperty
专门用于描述 UI 控件属性的,它具有以下特征:
- 不会产生
error
事件
- 一定在
MainScheduler
订阅(主线程订阅)
- 一定在
MainScheduler
监听(主线程监听)
- 共享状态变化