RxSwift 的特征序列

133 阅读4分钟

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 中最新的元素发送出来(如果不 存在最新的元素,就发出默认元素)。然后将随后产生的元素发送出来。

image.png

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 可以在日常开发中为我们避免很多麻烦,比如

  1. 有的事件序列遇到 error 事件就结束了,但是我们不希望他结束,此时将 Obaervable 转成 Driver,调用 asDriver函数,会强制要求我们传一个默认值,以防止在遇到 error 的时候序列被销毁。
  2. 在一个异步网络请求的回调中,我们拿到回调结果往往需要在主线程做一系列操作,driver 会默默的帮我们回到主线程。
  3. 如果同时多个 observer 订阅了 driver,Observable 的附加代码只会调用一次(比如 request 只会请求一次)