RxSwift源碼分析(六)-銷燬者Disposable

銷燬者簡介

可被清除的資源DisposableRxSwift的核心成員之一,它主要是用來清除再也不須要的資源。那麼下面來探索一下RxSwift是怎樣管理這些資源的生命週期呢。 api

  • 一般來講,一個序列若是發出了 error 或者 completed 事件,那麼全部內部資源都會被釋放,不須要咱們手動釋放。
  • 可是若是你須要提早釋放這些資源或取消訂閱的話,那麼你能夠對返回的可被清除的資源(Disposable) 調用 dispose 方法。
  • 不過官方推薦使用清除包(DisposeBag)來管理訂閱的生命週期,通常是把資源加入到一個全局的DisposeBag裏面,它跟隨着頁面的生命週期,當頁面銷燬時DisposeBag也會隨之銷燬,同時DisposeBag裏面的資源也會被一一釋放。
var disposeBag = DisposeBag() // 來自父類 ViewController

override func viewDidLoad() {
    super.viewDidLoad()

    ...

    usernameValid
        .bind(to: passwordOutlet.rx.isEnabled)
        .disposed(by: disposeBag)

    usernameValid
        .bind(to: usernameValidOutlet.rx.isHidden)
        .disposed(by: disposeBag)
}
複製代碼

銷燬者的實現探索

下面這一段代碼是常規的建立一個序列,而後訂閱,最後手動銷燬的流程。安全

let observable = Observable<Any>.create { (observer) -> Disposable in
    observer.onNext("七夕快樂")
    return Disposables.create {
        print("銷燬釋放了")
    }
}

let dispose = observable.subscribe(onNext: { (message) in
    print("有一條新消息:\(message)")
}, onError: { (error) in
    print("錯誤")
}, onCompleted: {
    print("完成")
}) {
    print("銷燬回調")
}

print("開始調用dispose")
dispose.dispose()
複製代碼
執行結果:
有一條新消息:七夕快樂
開始調用dispose
銷燬釋放了
銷燬回調
複製代碼
  • 首先能夠看到,在建立序列Observable<Any>.create方法有一個尾隨閉包,須要返回一個實現了Disposable協議的實例。
  • 進入到Disposables.create方法裏面看看
extension Disposables {
    public static func create(with dispose: @escaping () -> Void) -> Cancelable {
        return AnonymousDisposable(disposeAction: dispose)
    }
}
複製代碼
  • 建立了一個AnonymousDisposable對象並返回,很明顯,這是一個匿名銷燬者,跟建立序列的時候會建立一個匿名序列實現方式很是類似。
fileprivate final class AnonymousDisposable : DisposeBase, Cancelable {
    public typealias DisposeAction = () -> Void

    private let _isDisposed = AtomicInt(0)
    private var _disposeAction: DisposeAction?

    public var isDisposed: Bool {
        return isFlagSet(self._isDisposed, 1)
    }

    fileprivate init(_ disposeAction: @escaping DisposeAction) {
        self._disposeAction = disposeAction
        super.init()
    }

    fileprivate init(disposeAction: @escaping DisposeAction) {
        self._disposeAction = disposeAction
        super.init()
    }

    fileprivate func dispose() {
        if fetchOr(self._isDisposed, 1) == 0 {
            if let action = self._disposeAction {
                self._disposeAction = nil
                action()
            }
        }
    }
}
複製代碼
  • 初始化的時候把外界傳過來的閉包進行保存
  • 而後看到有一個dispose方法,fetchOr(self._isDisposed, 1) == 0這行代碼是控制if語句裏面只會進去一次。
  • fetchOr方法的具體實現:AtomicInt是繼承NSLock,在更改value值的時候加了一把鎖,保證線程安全,而後運用了或運算並保存結果。位運算更加的高效。
  • 最後先把self._disposeAction賦值給臨時變量action,而後置空self._disposeAction,再執行action()。這樣操做的緣由是若是_disposeAction閉包是一個耗時操做,也可以保證_disposeAction可以當即釋放。
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
    this.lock()
    let oldValue = this.value
    this.value |= mask
    this.unlock()
    return oldValue
}
複製代碼
final class AtomicInt: NSLock {
    fileprivate var value: Int32
    public init(_ value: Int32 = 0) {
        self.value = value
    }
}
複製代碼
  • 上面的流程,咱們是在序列的回調閉包:_subscriberHandle裏面,其實這個流程以前還有一個很是重要的流程:訂閱,進入到observable.subscribe方法
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 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()
        }
    }
    
    return Disposables.create(
        self.asObservable().subscribe(observer),
        disposable
    )
}
複製代碼
  • 首先建立了一個Disposable對象,並保存了銷燬回調閉包,當執行銷燬時,會把消息回調出去
  • 在發出錯誤和完成事件以後也會執行disposable.dispose(),這就證明了前面說的:一個序列若是發出了 error 或者 completed 事件,那麼全部內部資源都會被釋放,不須要咱們手動釋放。
  • 看最後一行代碼return Disposables.create( self.asObservable().subscribe(observer), disposable ),這裏返回的Disposable對象就是咱們外面手動調用dispose.dispose()方法的dispose對象,或者說是加入到全局的DisposeBag的銷燬者。
  • 跟蹤進入查看代碼
public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable {
    return BinaryDisposable(disposable1, disposable2)
}
複製代碼
  • 建立了一個二元銷燬者
func dispose() {
    if fetchOr(self._isDisposed, 1) == 0 {
        self._disposable1?.dispose()
        self._disposable2?.dispose()
        self._disposable1 = nil
        self._disposable2 = nil
    }
}
複製代碼
  • 當執行dispose()時會把2個銷燬者分別銷燬
  • 而後再來看看這個二元銷燬者建立時的第一個參數:self.asObservable().subscribe(observer)的返回值是什麼。來到Producer類的subscribe方法
let disposer = SinkDisposer()
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
複製代碼
  • 建立了一個sink的銷燬者SinkDisposer對象並返回,因此前面建立二元銷燬者的第二個參數就是它。通過以前對RxSwift核心邏輯的分析文章,咱們知道sink是鏈接序列和觀察者的橋樑,當sink銷燬後,序列和觀察者之間就沒法通信了。
  • 進入到self.run(observer, cancel: disposer)
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)
}
複製代碼
  • 建立了一個AnonymousObservableSink對象,並保存了上一步建立的SinkDisposer對象。在AnonymousObservableSink的源碼裏面發現on方法中,當發出完成和錯誤信號後,會當即執行dispose進行銷燬,因此一旦咱們的序列發出完成或者錯誤信號後就沒法再次響應了!
  • 執行sink.run(self),方法裏面執行的是parent._subscribeHandler(AnyObserver(self))_subscribeHandler閉包就是外面建立序列Observable<Any>.create的尾隨閉包,因此返回值就是Disposables.create {print("銷燬釋放了")}
  • 進入到setSinkAndSubscription方法
func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
    self._sink = sink
    self._subscription = subscription

    let previousState = fetchOr(self._state, DisposeState.sinkAndSubscriptionSet.rawValue)
    if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
        rxFatalError("Sink and subscription were already set")
    }

    if (previousState & DisposeState.disposed.rawValue) != 0 {
        sink.dispose()
        subscription.dispose()
        self._sink = nil
        self._subscription = nil
    }
}
複製代碼
  • 保存了兩個屬性 : sinksubscription,就是上一步返回的銷燬者和AnonymousObservableSink對象,AnonymousObservableSink裏面保存了sink的銷燬者SinkDisposer
  • 根據記錄的一個狀態去判斷剛剛保存的這兩個屬性是否須要銷燬,須要的話就執行 dispose() 而後置空 nil
  • 那麼,當執行dispose.dispose()銷燬時銷燬的究竟是什麼呢
func dispose() {
    let previousState = fetchOr(self._state, DisposeState.disposed.rawValue)

    if (previousState & DisposeState.disposed.rawValue) != 0 {
        return
    }
    if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {

        sink.dispose()
        subscription.dispose()

        self._sink = nil
        self._subscription = nil
    }
}
複製代碼
  • 無論是系統銷燬仍是咱們手動銷燬都會執行dispose(),咱們查看 dispose() 得出: 就是把初始化的時候保存的兩個屬性進行銷燬而後置空。
  • RxSwift中,sink存放了序列和觀察者,來創建它們之間的響應關係,當把序列和觀察者之間的橋樑sink銷燬了,也就斷開了它們之間的響應關係,從而沒法再接收到消息。
  • 附上一張圖

總結

  • 一個序列若是發出了 error 或者 completed 事件,那麼全部內部資源都會被釋放,不須要咱們手動釋放。
  • 當執行銷燬時,銷燬的是序列和觀察者之間的響應關係,不是序列和觀察者對象自己
  • 若是是加入到disposeBag,是在disposeBag對象銷燬時,依次銷燬裏面存儲的東西
相關文章
相關標籤/搜索