PublishSubject
正如本次分享开头提到的 TestSubject ,他既可以作为事件序列被 Observer 监听,又可以作为 Observer 发出 on 方法产生事件序列。PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者。
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("")
输出结果
Subscription: 1 Event: next( )
Subscription: 1 Event: next( )
Subscription: 1 Event: next()
Subscription: 2 Event: next()
Subscription: 1 Event: next()
Subscription: 2 Event: next()
BehaviorSubject
BehaviorSubject 的实现方式和 PublishSubject 其实基本上是一样的,唯一的区别就是当观察者对 BehaviorSubject 进行订阅时,它会将源 Observable 中最新的元素发送出来(如果不 存在最新的元素,就发出默认元素)。然后将随后产生的元素发送出来。
BehaviorSubject 的实现细节很有意思,他持有了一个属性 element,并且每次接收到 next 信号,就把新的元素赋值给他。所以每次我们接收到的回放都是这个 element 值。具体 BehaviorSubject 是如何做到回放的呢?非常简单,就是在他每次收到订阅(subscribe)的时候,主动调一次
observer.on(.next(self.element)) // 相当于把上次的 element 又发射了一次
RxRelay
PublishRelay
他就是 PublishSubject 去掉了 completed 和 error 事件,同样的,既是可监听序列,也是观察者。
public final class PublishRelay<Element>: ObservableType {
private let subject: PublishSubject<Element>
// 省掉了 PublishSubject 的 onError, onCompleted 事件
public func accept(_ event: Element) {
self.subject.onNext(event)
}
public init() {
self.subject = PublishSubject()
}
/// Subscribes observer
public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
self.subject.subscribe(observer)
}
/// - returns: Canonical interface for push style sequence
public func asObservable() -> Observable<Element> {
self.subject.asObservable()
}
}
BehaviorRelay
BehaviorRelay 就是 BehaviorSubject 去掉终止事件 onError 或 onCompleted,参考 BehaviorSubject
Single
Single 要么只能发出一个元素,要么产生一个 error 事件,因为 single 的 subscribe 方法接收的事件类型 SingleEvent 是一个地地道道的 Swift 库中的 Result 枚举。如果他被某一个观察者 Observer 所监听,那么在收到 success 事件的时候,这个事件序列就已经结束了,所以它只能发射一个元素。
switch event {
case .success(let element):
// 结束了
observer.on(.next(element))
observer.on(.completed)
case .failure(let error):
observer.on(.error(error))
}
一个最直白的应用场景,就是执行 HTTP 请求,返回一个 Result 结果。
Completable
Completable 要么只能产生一个 completed 事件,要么产生一个 error 事件。 Completable 适用于那种你只关心任务是否完成,而不需要在意任务返回值的情况。它和 Observable 有点相似。 仔细想一想,Completable 其实在很多场景下都很有用,比如某一个定时器,如果超过了多长时间,就不再执行回调。此时使用 Completable 一方面语义更加清晰,另一方面在事件发出后,Completable 所引用的资源就已经被全部销毁了。下面是我们最新需求的一个例子,可以感受一下 Completable的威力:
let speed = Observable<CGFloat>.create { (observer) -> Disposable in
return Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).subscribe(onNext: { element in
var speed = element
// 第10秒以后 把 速度置为 0
if element > 10 {
speed = 0
}
print("speed = \(speed)")
observer.onNext(CGFloat(speed))
})
// throttle 可以控制采集频率,两秒钟采集一次
}.throttle(.seconds(2), scheduler: MainScheduler.instance)
var lastSentTime: Date?
var pastTime: TimeInterval = 0
let completable = Completable.create { event -> Disposable in
let dispose = speed.subscribe(onNext: { value in
guard value == 0.0 else { return }
if let lastSendingTime = lastSentTime {
pastTime = Double(Date().timeIntervalSinceNow) - Double(lastSendingTime.timeIntervalSinceNow)
} else {
lastSentTime = Date()
}
print("pastTime = \(pastTime)")
if pastTime >= 15.0 { // 速度为0的持续时间超过了 300 秒,发出事件
event(.completed)
}
})
// 我们把dispose加进去,是为了在 completable 销毁之后,把 speed 也销毁掉
return Disposables.create { dispose.dispose() }
}
completable.subscribe(onCompleted: {
// completable 序列即将被销毁,所持有的资源被清空
print("您已在原地停留15秒~")
}).disposed(by: bag)
Maybe
Maybe 介于 Single 和 Completable 之间,它要么只能发出一个 元素,要么产生一个 completed 事件,要么产生一个 error 事件。
适用场景: 如果遇到那种可能需要发出一个元素,又可能不需要发出时,就可以使用 Maybe。 这个我就想不到具体使用场景了~
Driver
Driver 主要是为了简化 UI 层的代码。不过如果我们遇到的序列具有以下特征,也可以使用它
- 不会产生 error 事件
- 一定在 MainScheduler 监听(主线程监听)
- 共享附加作用(自动实现了 share 方法)
driver 可以在日常开发中为我们避免很多麻烦,比如
- 有的事件序列遇到 error 事件就结束了,但是我们不希望他结束,此时将 Obaervable 转成 Driver,调用 asDriver函数,会强制要求我们传一个默认值,以防止在遇到 error 的时候序列被销毁。
- 在一个异步网络请求的回调中,我们拿到回调结果往往需要在主线程做一系列操作,driver 会默默的帮我们回到主线程。
- 如果同时多个 observer 订阅了 driver,Observable 的附加代码只会调用一次(比如 request 只会请求一次)