RxSwift 源码--Sink 理解

808 阅读7分钟

测试代码:

let dispose = Observable<Int>.create { (observer) -> Disposable in
    observer.onNext(1)
    observer.onCompleted()
        return Disposables.create()
    }.subscribe(onNext: { (i) in
        print("\(i)")
    }, onError: { (error) in
        print("\(error)")
    }, onCompleted: {
        print("complete")
    })

过程解析

创建源

关系如图,方框里的是类,上层的方框表示是父类,箭头表示持有关系。所以:

  1. 匿名源继承自 Producer
  2. 匿名源持有创建源的闭包 handler
final private class AnonymousObservable<Element>: Producer<Element> {
    typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable

    let _subscribeHandler: SubscribeHandler

    init(_ subscribeHandler: @escaping SubscribeHandler) {
        self._subscribeHandler = subscribeHandler
    }

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

创建观察者

匿名观察者的创建:

let observer = AnonymousObserver<Element> { event in
    switch event {
    case .next(let value):
        onNext?(value)
    case .error(let error):
        if let onError = onError {
            onError(error)
        } else {
            Hooks.defaultErrorHandler(callStack, error)
        }
        disposable.dispose()
    case .completed:
        onCompleted?()
        disposable.dispose()
    }
}

匿名观察者:

final class AnonymousObserver<Element>: ObserverBase<Element> {
    typealias EventHandler = (Event<Element>) -> Void
    
    private let _eventHandler : EventHandler
    
    init(_ eventHandler: @escaping EventHandler) {
        self._eventHandler = eventHandler
    }

    override func onCore(_ event: Event<Element>) {
        return self._eventHandler(event)
    }
}

ObserverBase:

class ObserverBase<Element> : Disposable, ObserverType {
    private let _isStopped = AtomicInt(0)

    func on(_ event: Event<Element>) {
        switch event {
        case .next:
            if load(self._isStopped) == 0 {
                self.onCore(event)
            }
        case .error, .completed:
            if fetchOr(self._isStopped, 1) == 0 {
                self.onCore(event)
            }
        }
    }

    func onCore(_ event: Event<Element>) {
        rxAbstractMethod()
    }

    func dispose() {
        fetchOr(self._isStopped, 1)
    }
}
  1. 匿名观察者继承自 ObserverBase
  2. 匿名观察者持有 handler,但是这个 handler 不是调用者给的那3个闭包(subscribe, onError, onCompleted),handler 的参数是 event,在 handler 中,根据 event 类型,分别调用了那3个闭包

订阅

订阅方法:

public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
        -> Disposable {
    let disposable: Disposable
            
    if let disposed = onDisposed {
        disposable = Disposables.create(with: disposed)
    } else {
        disposable = Disposables.create()
    }
    let callStack = Hooks.recordCallStackOnError ? Hooks.customCaptureSubscriptionCallstack() : []
            
    // 省略掉匿名观察者的初始化,上面有
    return Disposables.create(
        self.asObservable().subscribe(observer),
        disposable
    )
}

Disposables.create 返回的是 BinaryDisposable。

它就是持有了两个 Disposable,并且同步处理两个Disposable,该 dispose 时一起 dispose,该释放时一起释放,就是把两个 Disposable 合并成一个了。

self.asObservable().subscribe(observer) 调用的方法是匿名源的订阅方法,这个方法定义在 Producer 中:

class Producer<Element> : Observable<Element> {
    override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
        // 只保留了重要的代码
        let disposer = SinkDisposer()
        let sinkAndSubscription = self.run(observer, cancel: disposer)
        disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
        return disposer
    }
}

这里面又用到了 SinkDisposer,SinkDisposer 保存了一个 Sink,和一个 Subscription,这个就有点迷惑了,Sink 和 Subscription 都是 Disposable 类型,那它们两个什么含义呢?SinkDisposer 是什么作用呢

接下来调用到的 run 方法是在匿名源中的:

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

这里又出来一个匿名源Sink:

final private class AnonymousObservableSink<Observer: ObserverType>: Sink<Observer>, ObserverType {
    typealias Element = Observer.Element 
    typealias Parent = AnonymousObservable<Element>

    // state
    private let _isStopped = AtomicInt(0)

    override init(observer: Observer, cancel: Cancelable) {
        super.init(observer: observer, cancel: cancel)
    }

    func on(_ event: Event<Element>) {
        switch event {
        case .next:
            if load(self._isStopped) == 1 {
                return
            }
            self.forwardOn(event)
        case .error, .completed:
            if fetchOr(self._isStopped, 1) == 0 {
                self.forwardOn(event)
                self.dispose()
            }
        }
    }

    func run(_ parent: Parent) -> Disposable {
        return parent._subscribeHandler(AnyObserver(self))
    }
}

代码基本上贴完了,这些东西我看了非常久才看得透彻。

从闭包到响应式编程

创建源步骤中得到的是匿名源对象,并且之后调用的订阅方法也是它的,但其实观察者订阅到的源并不是它。

毕竟源并不是一个闭包那么简单的,它还要管理它的状态。

AnonymousObservableSink 的这段代码可以看出:

func run(_ parent: Parent) -> Disposable {
    return parent._subscribeHandler(AnyObserver(self))
}

是 AnyObserver 订阅的匿名源,而 AnyObserver 没做什么特别的,它就只是保存一个 EventHandler 类型的闭包,有消息来时,它再调用这个闭包,也就是把 AnonymousObservableSink 包装成观察者类型。

而观察者是被 AnonymousObservableSink 拿着的。

对象的持有关系是这样的:

  1. 匿名源 持有 SubscribeHandler
  2. SubscribeHandler 持有 AnyObserver
  3. AnyObserver 持有 EventHandler
  4. EventHandler 是 AnonymousObservableSink 的方法
  5. AnonymousObservableSink 持有 Observer

所以当事件发生时,事件的传递过程是这样:

匿名源->AnonymousObservableSink->Observer

所以从闭包到响应式编程是通过 AnonymousObservableSink 做到的,AnonymousObservableSink 把自己伪装成观察者,并且持有想订阅匿名源的观察者。

那为什么要在匿名源和观察者之间强行加个小三儿呢,因为这个小三替匿名源管理了状态,当 error/completed 发生时,AnonymousObservableSink 就会调用 它持有的 _cancel 的 dispose 方法,并把自己的状态设置成 disposed,以后再接收到消息,它也不会向下传递了。

所以我认为 Sink 的作用就是桥接命令式编程和响应式编程的,但是它的作用是不是仅限于源,我还得打个问号。

而 _cancel 就是 SinkDisposer。(一会儿再讲)

观察者的转换过程比较简单,通过 ObserverBase 控制的状态。

从内存角度看看

从xcode的 memory graph 可以看出持有关系:

  1. BinaryDispoable 被 disposeBag 持有
  2. SinkDisposer 和 匿名源Sink 互相引用
  3. 还有源和观察者的 Dispose 没有被显示出来,因为 Dispose 是结构体,不需要管理内存

源被 SinkDisposer +16 持有,这是个什么东西?我翻遍了 SinkDisposer,也没找到持有源的地方。

于是测试:

var observable: Observable<Int>? = nil
observable = Observable<Int>.create { (observer) -> Disposable in
    observer.onNext(1)
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { 
        // 在这里打断点, 看看 1s 之后,源还在不在
        observer.onCompleted()
    }
    let dispose = Disposables.create()
    return dispose
}
if let o = observable {
    let dispose = o.subscribe(onNext: { (i) in
        print("\(i)")
    }, onError: { (error) in
        print("\(error)")
    }, onCompleted: {
        print("complete")
    })
    dispose.disposed(by: disposeBag)
    }
}

发现在一秒钟之后,源已经被释放了。

那就先不考虑上面的 SinkDisposer +16,搞不好是SinkDisposer的run方法也未可知呀

每个类型都是什么作用

  1. 匿名源:保存 SubscribeHandler
  2. Producer:匿名源需要把 SubscribeHandler 转换成源,但是这个事情不仅仅是匿名源需要的,其他类也会需要的,所以就把转换的方法提取成 Producer 类。但是 Producer 没办法包揽一切,还是需要匿名源决定怎么转换的,匿名源是通过重写 Producer 的 run 方法处理转换的。
  3. 匿名源Sink:但是为了保持匿名源的纯净,转换工作是匿名源Sink在做的,匿名源只是在 run 中调用匿名源 Sink,并把处理结果给 Producer。匿名源Sink中处理了 stop 状态
  4. 观察者和 ObserverBase 没什么好说的
  5. BinaryDisposable:当 disposeBag 被销毁时,dispose() 要从 BinaryDisposable 开始调起,传给观察者、观察者的源,所以就用二叉Disposable 把它们包在一起
  6. SinkDisposer:Sink 的 Disposer,它持有 sink 和 源的 dispose,会同时调用两者的 dispose(),跟BinaryDisposable 有点类似

这里面 SinkDisposer 和 BinaryDisposable 显得有点奇怪,以下是我的理解:

dispose消息来源有两个:DisposeBag 销毁时发出的,和源发出的。

1. DisposeBag 销毁时 要通知到:源的 dispose,观察者的 dispose,源(注意不通知观察者)

用 BinaryDisposable 保存 观察者的 dispose 方法 和 SinkDisposer

Sink 我们前面的理解是:对于外面来说,可以认为它就是源,所以 SinkDisposer 就可以认为是源的 disposer,它是用来 dispose 源的。它保存了源的 dispose 和 匿名源Sink(直接认为就是源吧)

匿名源是帮匿名源处理状态的,它收到 dispose() 后就会改改自己的状态。

2. 源发出 complete 或者 error 时 要通知到:源的 dispose,观察者的 dispose,源、观察者

disposebag销毁时,是直接调用dispose方法通知到各方的,源发出complete或者error 是通过 on(event:) 方法传递的。

源发出消息,到了匿名源sink这里,它会改改自己的状态并把消息传给观察者。

观察者收到event后,也会改改自己的状态,然后调用观察者的dispose方法。

还差源的dispose方法没有调用,匿名源sink持有sinkDisposer,会通知到sinkDisposer的。

咦?那不就有一个循环了:匿名源sink调用SinkDisposer的dispose,SinkDisposer又会在它的dispose方法里调用匿名源sink的dispose。

是滴,的确是这样,不过在SinkDisposer和匿名源sink里都有状态判断,状态是已dispose的话,就不会再调用下去了。

Sink/Dispose 是什么

  1. Sink 是 SubscribeHandler 和 观察者的桥梁,它的主要作用是管理源的状态
  2. subscription 应该都是 Disposable 类型的,是订阅后源的dispose,dispose里一般做的事情都是:当取消订阅时,源会做一些回收工作,或者更改状态

我的手稿