和 Observable 一样,观察者也存特征观察者,例如:
·Binder
AnyObserver
AnyObserver 可以用来描叙任意一种观察者。
用例
URLSession.shared.rx.data(request: URLRequest(url: URL.init(string: "https://api.github.com/repos/")!)).subscribe { data in
} onError: { error in
} onCompleted: {
}.disposed(by: disposeBag)
可以看作
let observer: AnyObserver<Data> = AnyObserver {
(event) in
switch event {
case .next(let data):
print("data")
case .error(let error):
print("error")
case .completed:
print("completed")
}
}
使用observer
URLSession.shared.rx.data(request: URLRequest(url: URL.init(string: "https://api.github.com/repos/")!)).subscribe(observer)
.disposed(by: disposeBag)
用例2
let passwordVaild = passwordTextFiled.rx.text.orEmpty
.map {
$0.count >= minimalPasswordLength
}
.share(replay: 1)
let observer1: AnyObserver<Bool> = AnyObserver {
(evnt) in
switch evnt {
case .next(let isHidden):
self.passwordVaildLb.isHidden = isHidden
default:
break
}
}
passwordVaild.bind(to: observer1)
.disposed(by: disposeBag)
Binder
Binder 主要有以下两个特征: 不会处理错误事件 确保绑定都是在给定 Scheduler 上执行(默认MainScheduler ) 一旦产生错误事件,在调试环境下将执行 fatalError ,在 发布环境下将打印错误信息。
let observer1: AnyObserver<Bool> = AnyObserver {
(evnt) in
switch evnt {
case .next(let isHidden):
self.passwordVaildLb.isHidden = isHidden
default:
break
}
}
passwordVaild.bind(to: observer1)
.disposed(by: disposeBag)
由于这个观察者是一个 UI 观察者,所以它在响应事件时, 只会处理 next 事件,并且更新 UI 的操作需要在主线程上 执行。 因此一个更好的方案就是使用 Binder :
let observer2: Binder<Bool> = Binder(passwordVaildLb) { (view, isHidden) in
view.isHidden = isHidden
}
passwordVaild
.bind(to: observer2)
.disposed(by: disposeBag)
Binder 可以只处理 next 事件,并且保证响应 next 事件 的代码一定会在给定 Scheduler 上执行,这里采用默认的
MainScheduler 。
复用
由于页面是否隐藏是一个常用的观察者,所以应该让所有的UIView 都提供这种观察者:
extension Reactive where Base: UIView {
public var isHidden: Binder<Bool> {
return Binder(self.base) { view, isHidden in
view.isHidden = isHidden
}
}
}
passwordTextFiled.rx.text.orEmpty
.map{$0.count >= minimalUsernameLength}
.bind(to: passwordVaildLb.rx.isHidden)
.disposed(by: disposeBag)
这样你不必为每个 UI 控件单独创建该观察者。这就是
passwordVaildLb.rx.isHidden的由来,许多 UI 观察 者 都是这样创建的:
·按钮是否可点击 button.rx.isEnabled:
extension Reactive where Base: UIControl {
public var isEnable: Binder<Bool> {
return Binder<self.base> { control, value in
control.isEnable = value
}
}
}
·label 的当前文本 label.rx.text :
extension Reactive where Base: UILabel {
public var text: Binder<String?> {
return Binder(self.base) { lable, text in
lable.text = text
}
}
}
Observable & Observer 既是可监听序 列也是观察者
在我们所遇到的事物中,有一部分非常特别。它们既是可监 听序列也是观察者。 例如: textField 的当前文本。它可以看成是由用户输入, 而产生的一个文本序列。也可以是由外部文本序列,来控制 当前显示内容的观察者:
// 作为可监听序列
let observable = textField.rx.text
observable.subscribe(onNext: { text in show(text:
text) })
// 作为观察者
let observer = textField.rx.text
let text: Observable<String?> = ...
text.bind(to: observer)
有许多 UI 控件都存在这种特性,例如: switch 的开关状 态, segmentedControl 的选中索引号, datePicker 的选中 日期等等。
框架里面定义了一些辅助类型,它们既是可监听序列 也是观察者。如果你能合适的应用这些辅助类型,它们就可 以帮助你更准确的描述事物的特征:
- AsyncSubject
- PublishSubject
- ReplaySubject
- BehaviorSubject
- ControlProperty
AsyncSubject
AsyncSubject 将在源 Observable 产生完成事件后,发出最 后一个元素(仅仅只有最后一个元素),如果源Observable 没有发出任何元素,只有一个完成事件。那AsyncSubject 也只有一个完成事件。
let subject = AsyncSubject<String>()
subject.subscribe { string in
print(string)
}.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
subject.onCompleted()
//打印
next(3)
completed
PublishSubject
PublishSubject 将对观察者发送订阅后产生的元素,而在订阅 前发出的元素将不会发送给观察者。如果你希望观察者接收 到所有的元素,你可以通过使用 Observable 的 create 方 法来创建 Observable ,或者使用 ReplaySubject。
let subject = PublishSubject<String>()
subject.subscribe { event in
print("Subscription: 1 Event:",event)
}.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
subject.subscribe { event in
print(print("Subscription: 2 Event:",event))
}.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
打印结果
Subscription: 1 Event: next(1)
Subscription: 1 Event: next(2)
Subscription: 1 Event: next(1)
Subscription: 2 Event: next(1)
()
Subscription: 1 Event: next(2)
Subscription: 2 Event: next(2)
()
ReplaySubject
ReplaySubject 将对观察者发送全部的元素,无论观察者是何 时进行订阅的。 这里存在多个版本的 ReplaySubject ,有的只会将最新的 n 个 元素发送给观察者,有的只会将限制时间段内最新的元素发 送给观察者。
如果把 ReplaySubject 当作观察者来使用,注意不要在多个 线程调用 onNext , onError 或 onCompleted 。这样会导 致无序调用,将造成意想不到的结果。
let subject = ReplaySubject<String>.create(bufferSize: 1)
subject.subscribe { event in
print(print("Subscription: 1 Event:",event))
}.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
subject.subscribe { event in
print(print("Subscription: 2 Event:",event))
}.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
打印
Subscription: 1 Event: next(1)
()
Subscription: 1 Event: next(2)
()
Subscription: 2 Event: next(2)
()
Subscription: 1 Event: next(1)
()
Subscription: 2 Event: next(1)
()
Subscription: 1 Event: next(2)
()
Subscription: 2 Event: next(2)
()
BehaviorSubject
当观察者对 BehaviorSubject 进行订阅时,它会将源
Observable 中最新的元素发送出来(如果不存在最新的元 素,就发出默认元素)。然后将随后产生的元素发送出来。
如果源 Observable 因为产生了一个 error 事件而中止,BehaviorSubject 就不会发出任何元素,而是将这个 error事件发送出来。
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("🍊")
Subscription: 1 Event: next(🔴)
Subscription: 1 Event: next(🐶)
Subscription: 1 Event: next(🐱)
Subscription: 2 Event: next(🐱)
Subscription: 1 Event: next(🅰 )
Subscription: 2 Event: next(🅰 )
Subscription: 1 Event: next(🅱 )
Subscription: 2 Event: next(🅱 )
Subscription: 3 Event: next(🅱 )
Subscription: 1 Event: next( )
Subscription: 2 Event: next( )
Subscription: 3 Event: next( )
Subscription: 1 Event: next(🍊)
Subscription: 2 Event: next(🍊)
Subscription: 3 Event: next(🍊)
网友评论