07. RxSwift源码解读:Single、Completable、Maybe、Driver、Signal

今天分享一下Observable的几个变种的用法,解读其源码。这几个都是可观察序列,适用于不同的场景。

Single

Single只能发出一个成功和一个失败两种信号,分别是success()和error, 是对error complete onNext信号的变换,我们看看Single的create方法的代码:

    public static func create(subscribe: @escaping (@escaping SingleObserver) -> Disposable) -> Single {
        let source = Observable.create { observer in
            return subscribe { event in
                switch event {
                case .success(let element):
                    observer.on(.next(element))
                    observer.on(.completed)
                case .failure(let error):
                    observer.on(.error(error))
                }
            }
        }
        return PrimitiveSequence(raw: source)
    }

Single实际是对Observable的封装,内部包含Observable,而且Single只是一个别名,真实类型是PrimitiveSequence。

public typealias Single = PrimitiveSequence
public typealias SingleEvent = Result

Result 是Swift的自带枚举类型,包含success和failure两种case。
observer的 .next和.comleted 对应的就是.success, error对应failure,所以这个Single只能发出一个信号,特别适用于网路请求。

我们可以看看Single的真实类型PrimitiveSequence的源码:

public struct PrimitiveSequence {
    let source: Observable

    init(raw: Observable) {
        self.source = raw
    }
}

包含一个原始的序列source,它的asObservable返回的就是这个source,这样可切换到原始序列进行操作。PrimitiveSequence实际上并没有遵循ObservableType,它遵循的是ObservableConvertibleType。

Maybe和Completable

和Single类似,Maybe和Completable的真实类型也是PrimitiveSequence,区别在于:

  • Maybe可以发出succes,error,和completed事件,它要么只能发出一个元素,要么产生一个 completed 事件,要么产生一个 error 事件。如果你遇到那种可能需要发出一个元素,又可能不需要发出时,就可以使用 Maybe。
  • Completable,只能发出一个complete事件或一个error事件。Completable 适用于那种你只关心任务是否完成,而不需要在意任务返回值的情况。它和 Observable 有点相似。

Driver和Signal

Driver和Signal也是个特征序列,它们主要是为了简化UI层的代码。
不过如果你遇到的序列具有以下特征,你也可以使用它:

  • 不会产生 error 事件
  • 一定在 MainScheduler 监听(主线程监听)
  • [共享附加作用]

这些都是驱动 UI 的序列所具有的特征。

共享附加作用的意思是,观察者共享源 Observable,并且缓存最新的 n 个元素,将这些元素直接发送给新的观察者;它使用share操作符实现此功能。

我们看看Driver的源码:

public typealias Driver = SharedSequence

public struct DriverSharingStrategy: SharingStrategyProtocol {
    public static var scheduler: SchedulerType { SharingScheduler.make() }
    public static func share(_ source: Observable) -> Observable {
        source.share(replay: 1, scope: .whileConnected)
    }
}

extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingStrategy {
    /// Adds `asDriver` to `SharingSequence` with `DriverSharingStrategy`.
    public func asDriver() -> Driver {
        self.asSharedSequence()
    }
}

我们看到Driver也是个别名,真实类型是SharedSequence,DriverSharingStrategy类似一个策略表示Driver共享序列的策略是什么,这里看到Driver共享序列的策略是

source.share(replay: 1, scope: .whileConnected)

回放个数为1,scop:.whileConnected。

关于share操作符已经在之前的文章中详细讲解过,这里不再重复

当我们将序列转换为Driver时一般使用.asDriver(onErrorJustReturn: 1), 我们看看源码:

public func asDriver(onErrorJustReturn: Element) -> Driver {
        let source = self
            .asObservable()
            .observe(on:DriverSharingStrategy.scheduler)
            .catchAndReturn(onErrorJustReturn)
        return Driver(source)
    }

这里选择DriverSharingStrategy.scheduler这个调度器执行通知,scheduler方法的实现是:

{ SharingScheduler.make() }

make的实现是:

MainScheduler()

在主线程调度执行!这样保证UI事件通知是在主线程执行。接着执行.catchAndReturn(onErrorJustReturn)操作符:

public func catchAndReturn(_ element: Element)
        -> Observable {
        Catch(source: self.asObservable(), handler: { _ in Observable.just(element) })
    }

返回一个Catch类型实例,Catch也是个Observable,它继承自Producer,保存了原始source和handler,实现了run方法:

    override func run(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
        let sink = CatchSink(parent: self, observer: observer, cancel: cancel)
        let subscription = sink.run()
        return (sink: sink, subscription: subscription)
    }

这里会执行CatchSink的run方法:

    func run() -> Disposable {
        let d1 = SingleAssignmentDisposable()
        self.subscription.disposable = d1
        d1.setDisposable(self.parent.source.subscribe(self))

        return self.subscription
    }

这里关键代码是:self.parent.source.subscribe(self), 调用元素序列的subscribe同时传入当前对象,而当前对象即CatchSink实现了on方法:

    func on(_ event: Event) {
        switch event {
        case .next:
            self.forwardOn(event)
        case .completed:
            self.forwardOn(event)
            self.dispose()
        case .error(let error):
            do {
                let catchSequence = try self.parent.handler(error)

                let observer = CatchSinkProxy(parent: self)
                
                self.subscription.disposable = catchSequence.subscribe(observer)
            }
            catch let e {
                self.forwardOn(.error(e))
                self.dispose()
            }
        }
    }

在之前的文章中已经反复说过,CatchSink作为observer传入subscribe,则执行subscribe时,如果发送事件时会调用该类(CatchSink)的on方法,分析下on方法实现:
当事件类型是.next和.completed时,原样转发此事件,而当事件类型是error时,则执行handler,并执行handler返回值的subscribe方法,我们知道handler 方法返回一个Observable.just(element),所以当发送error时,将error事件转换成正常onNext的事件,发送element。发送element的工作交给CatchSinkProxy代理来完成,代理方法on中的实现如下:

func on(_ event: Event) {
        self.parent.forwardOn(event)
        
        switch event {
        case .next:
            break
        case .error, .completed:
            self.parent.dispose()
        }
    }

先执行被代理对象的forwardOn,接着如果是next则不做任何事情,因为已经执行了被代理对象的forwardOn,如果遇到error则执行被代理对象的dispose(). 释放相关资源。说白了catchAndReturn的功能是处理错误事件,将其转成一个正常的onNext事件。

回到asDriver代码实现地方,上面已经讲解完了catchAndReturn,接着调用Driver(source):

    init(_ source: Observable) {
        self.source = SharingStrategy.share(source)
    }

这里调用了DriverSharingStrategy的share操作符。DriverSharingStrategy是作为范型被确定的。DriverSharingStrategy的代码上面已经给出:source.share(replay: 1, scope: .whileConnected), 缓存是1个。所以Driver的功能就是组合observe,cacheError,share:保证在主线程监听,不会产生错误事件,共享附加作用。

Driver序列一般使用drive进行订阅。它的实现在SharedSequenceConvertibleType的扩展中,而且限定了SharingStrategy == DriverSharingStrategy,所以drive只能被Driver调用,我们看看drive实现:

Driver的真实类型是SharedSequence,而SharedSequence遵循了
SharedSequenceConvertibleType,所以它能调用drive方法。

public func drive(_ observers: Observer...) -> Disposable where Observer.Element == Element? {
        MainScheduler.ensureRunningOnMainThread(errorMessage: errorMessage)
        return self.asSharedSequence()
                   .asObservable()
                   .map { $0 as Element? }
                   .subscribe { e in
                    observers.forEach { $0.on(e) }
                   }
    }

这里先确保在主线程执行,这里是对订阅方法的包装,使用了以下操作符:

  • asSharedSequence 返回自身Driver对象
  • asObservable 返回Driver所保存的source,即原始序列
  • map 将元素转换成可选类型,drive有了两个方法实现,一个有map的一个是没有map的,当观察者的元素类型 是序列元素类型的可选类型时,则使用map先把序列的元素类型转成可选类型,否则如果一致则不需要map。
  • subscribe 调用观察者的on方法,通知所有观察者。

Signal

Signal和Driver非常类似,唯一的区别是,Driver对新观察者回放(重新发送)上一个元素,而 Signal 不会对新观察者回放上一个元素。
从代码中就能看出区别:我们找到SignalSharingStrategy结构体,它的share方法实现是:

public static func share(_ source: Observable) -> Observable {
        source.share(scope: .whileConnected)
    }

SignalSharingStrategy与DriverSharingStrategy类似,从上面代码可以看出Signal的共享策略是没有缓存(replay==0),这是唯一区别。
所以一般情况下状态序列我们会选用 Driver 这个类型,事件序列我们会选用 Signal 这个类型。
比如UITextField的text改变事件序列就是状态序列,它会发送text值。UIButton点击事件序列是事件序列,它没有状态,产生事件但不发送元素。

Signal一般使用emit进行订阅,作用和代码与drive基本一样,过~~~

你可能感兴趣的:(07. RxSwift源码解读:Single、Completable、Maybe、Driver、Signal)