上篇文章 mojito: 麻煩給個人愛人來一份 RxSwiftgit
沒有說起 DisposeBag
回收機制github
緣由有其二api
一是由於安全
時間過短,我沒來及看bash
二是由於閉包
文章過長,必口腔潰瘍ide
話很少說,來的都是回頭客post
看一下經典案例fetch
let obable = Observable<String>.create { observer -> Disposable in
observer.onNext("dispose") # step1
observer.onCompleted() # step2
return Disposables.create {
print("Disposables 釋放") # step6
}
}
_ = obable.subscribe(onNext: { (str) in
print("序列" + str) # step3
}, onError: { _ in
}, onCompleted: {
print("完成回調") # step4
}, onDisposed: {
print("銷燬回調") # step5
})
// 打印順序 序列dispose -> 完成回調 -> 銷燬回調 -> Disposables 釋放
複製代碼
Q 1:
爲何訂閱建立時 閉包返回值是 Disposable
類型 ?ui
先理清一些概念
Disposable
# 名爲 Disposable 的協議,定義一個重要的方法 dispose
public protocol Disposable {
# 處理 回收資源.
func dispose()
}
複製代碼
Disposables
# Disposables 是 結構體
public struct Disposables {
private init() {}
}
# Disposables 擴展 create,返回值 AnonymousDisposable 對象
# 銷燬者1
extension Disposables {
public static func create(with dispose: @escaping () -> Void) -> Cancelable {
return AnonymousDisposable(disposeAction: dispose)
}
}
複製代碼
Disposables.create
,建立了 匿名銷燬者 AnonymousDisposable
對象, 將閉包 step6
傳入
返回值是 Cancelable
類型
# 名爲 Cancelable 的協議,繼承 Disposable
public protocol Cancelable : Disposable {
# 資源是否被銷燬過.
var isDisposed: Bool { get }
}
複製代碼
再看一下 AnonymousDisposable
# 繼承了 DisposeBase 和 Cancelable,同時擁有 isDisposed & dispose()
private final class AnonymousDisposable : DisposeBase, Cancelable {
# Disposables.create 建立的閉包
public typealias DisposeAction = () -> Void
private let _isDisposed = AtomicInt(0)
private var _disposeAction: DisposeAction?
# 是否被銷燬
public var isDisposed: Bool {
return isFlagSet(self._isDisposed, 1)
}
# 保存閉包
private 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()
}
}
}
}
複製代碼
AtomicInt(0)
: 繼承 NSLock
, 賦值原始值爲 0
fetchOr
和 isFlagSet
都是 AtomicInt 類 的方法,都是線程安全
的
isFlagSet
:
func isFlagSet(_ this: AtomicInt, _ mask: Int32) -> Bool {
return (load(this) & mask) != 0
}
# 當 `self._isDisposed` 不爲0 的時候,也就是 被銷燬過
# 則 isFlagSet 返回 true,即 isDisposed 爲true
複製代碼
fetchOr
:
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
this.lock()
let oldValue = this.value
this.value |= mask
this.unlock()
return oldValue
}
# 進行 位運算 | ,只有當第一次爲 0 的時候,返回 oldValue 0
# 外界等式 成立
# newValue 爲 位運算以後的值 1,下次等式 就不等於 0
# 目的:只銷毀一次
複製代碼
dispose()
if let action = self._disposeAction {
self._disposeAction = nil
action()
}
# 臨時變量 action 保存 外界閉包
# 外界閉包 置nil
# 執行閉包
複製代碼
到這裏,咱們小結一下
Disposables.create
是 _subscribeHandler
閉包執行回調時,開始執行的_subscribeHandler
,勢必產生一個匿名銷燬者 AnonymousDisposable
AnonymousDisposable
實例,持有外界 銷燬閉包
AnonymousDisposable
,具備 銷燬的能力且只會銷燬一次
,以及 是否銷燬
的判斷銷燬者繼承鏈以下:
看到這裏就產生了第二個問題
Q 2:
dispose
何時調用 ?
時間回溯到 上篇的 subscribe
public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
-> Disposable {
let disposable: Disposable
# 將外界傳入的 onDisposed 閉包 , 即 print("銷燬回調")
# 生成 匿名銷燬者 AnonymousDisposable 實例
if let disposed = onDisposed {
disposable = Disposables.create(with: disposed)
} else {
disposable = Disposables.create()
}
let observer = AnonymousObserver<Element> { event in
switch event {
...省略
case .error(let error):
disposable.dispose()
case .completed:
disposable.dispose()
}
}
# 又 return 一個 Disposables.create
return Disposables.create(
self.asObservable().subscribe(observer),
disposable # 銷燬者2 onDisposed
)
}
複製代碼
不難看出,外界調用 subscribe
的時候,將 onDisposed 閉包傳入
而 subscribe
的返回值 也是 Disposable
類型,也是經過 Disposables.create
返回
定睛一看
這個 Disposables.create
, 有2個
參數
奇怪的事情發生了
點進去
extension Disposables {
# 經過2個銷燬者 ,生成一個新的銷燬者
public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable {
return BinaryDisposable(disposable1, disposable2)
}
}
複製代碼
不是看在一個爹的份上,你祖墳今天可能沒了
Disposables.creat 銷燬者1 說到
BinaryDisposable
銷燬者,和以前分析的 AnonymousDisposable
一模一樣,這裏就不分析了
private final class BinaryDisposable : DisposeBase, Cancelable {
....
# 只是內部多了一個參數
var isDisposed: Bool {
return isFlagSet(self._isDisposed, 1)
}
func dispose() {
if fetchOr(self._isDisposed, 1) == 0 {
self._disposable1?.dispose()
self._disposable2?.dispose()
self._disposable1 = nil
self._disposable2 = nil
}
}
}
複製代碼
問題又來到了這個 二元銷燬者
的第一個參數 self.asObservable().subscribe(observer)
能夠在 Producer
中 找到它的身影
override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
# 管道清潔工
# 返回一個 disposer 實例,在它釋放時,釋放管道內 全部引用
let disposer = SinkDisposer()
# 把 disposer 和 訂閱者 傳入 序列AnonymousObservable 的 run 中
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
}
複製代碼
建立了一個 管道清潔工 SinkDisposer
實例 disposer ,經過調用 AnonymousObservable 的 run
,將生成的 sink
和 subscription
分別持有
並返回 disposer
AnonymousObservable
中
final private class AnonymousObservable<Element>: Producer<Element> {
override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
# 經過上面傳入的 銷燬者,和訂閱者 生成匿名觀察管道
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
# 調用run ,也就是 執行 _subscribeHandler 閉包 ,將返回值 賦值給subscription
# subscription 指的是 銷燬者1
let subscription = sink.run(self)
return (sink: sink, subscription: subscription)
}
}
複製代碼
AnonymousObservableSink 繼承於 Sink
,Sink 一樣繼承於 Disposable
,表明了 AnonymousObservableSink
一樣具備 dispose()
的能力
老師,我暈了
能不能把 DisposeBag
先給我
我吐一下
Q 3
: AnonymousObservableSink
和 SinkDisposer
之間的關係是什麼?
A 3:
SinkDisposer 將本身的實例,經過匿名觀察序列,傳入 管道 AnonymousObservableSink
中,管道 Sink
擁有最終解釋權
意味着當外界執行訂閱subscribe
的時候, 會creat 一個 Disposables
元祖
Disposables
元祖內包含 :
由於加入了 Sink
的概念,Sink 做爲轉換者,處理了 序列 和訂閱者 以及 銷燬者之間的聯繫
若是把 Sink
比做 一棟大廈
那 SinkDisposer
就是大廈內的清潔工 ,SinkDisposer
負責處理大廈一切 雜物,但調度能力及解釋權
仍是歸大廈 Sink
所屬
private final class SinkDisposer: Cancelable {
private enum DisposeState: Int32 {
case disposed = 1
case sinkAndSubscriptionSet = 2
}
# 初始值爲 0
private let _state = AtomicInt(0)
private var _sink: Disposable?
private var _subscription: Disposable?
# 外界先設置 setSinkAndSubscription
func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
self._sink = sink
self._subscription = subscription
# 0 | 2 ,第一次返回oldValue 0,previousState 爲 0
# _state 賦值爲 2
let previousState = fetchOr(self._state, DisposeState.sinkAndSubscriptionSet.rawValue)
# 第一次 previousState 爲0, 0 & 2 = 0,繼續走
if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
rxFatalError("Sink and subscription were already set")
}
# 0 & 1 = 0,不進 if
if (previousState & DisposeState.disposed.rawValue) != 0 {
sink.dispose()
subscription.dispose()
self._sink = nil
self._subscription = nil
}
}
# 銷燬時調用,上面方法已走過一次
func dispose() {
# 在初次調用 setSinkAndSubscription 後, _state 爲2, 2 | 1 = 3, fetchOr 返回舊值 2 ,_state 變爲 3
# previousState 爲 2
let previousState = fetchOr(self._state, DisposeState.disposed.rawValue)
# 2 & 1 = 0,不進 if, 繼續走
if (previousState & DisposeState.disposed.rawValue) != 0 {
return
}
# 2 & 2 = 2, 知足條件,進 if ,分別 dispose
if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
# AnonymousObservableSink 調用 dispose
sink.dispose()
# 銷燬者1 調用 dispose
subscription.dispose()
# 銷燬後,分別置nil
self._sink = nil
self._subscription = nil
}
}
}
複製代碼
Q 1:
爲何訂閱建立時 閉包返回值是 Disposable 類型 ?
Disposable 類型 指的是 匿名銷燬者,
即銷燬者1
。由於想在序列建立的時候,就給它挖好墳墓,立好墓碑
如 燼
所說
我於殺戮之中盛放,亦如黎明中的花朵
死不重要,帥就完事了
Q 2:
dispose
何時調用 ?
在本文中,顯式調用了 onCompleted
,即 執行 subscribe
的 onCompleted閉包
,而且接着 調用
disposable.dispose()
case .completed:
onCompleted?()
disposable.dispose() # 銷燬者2
}
複製代碼
即 打印順序爲 完成回調 -> 銷燬回調
而 此時的 發出onCompleted
信號,必然會順着 水管 流到 AnonymousObservableSink
,調用 sink 的on
,即
case .error, .completed:
if fetchOr(self._isStopped, 1) == 0 {
self.forwardOn(event)
self.dispose() # 調用父類 Sink 的 dispose,父類調用 SinkDisposer 的 dispose
}
}
複製代碼
那麼這時 SinkDisposer
就會對 sink 和 銷燬者1 ,進行銷燬
因此最後打印 銷燬者
1 的 閉包 -> Disposables 釋放
執行順序細節
這裏衍生出 Q 4
: 若是不顯 式 調用 onCompleted
呢? 改成
let obable = Observable<String>.create { observer -> Disposable in
observer.onNext("dispose")
// observer.onCompleted()
return Disposables.create {
print("Disposables 釋放")
}
}
let dispose = obable.subscribe(onNext: { (str) in
print("序列" + str)
}, onError: { _ in
print("錯誤回調")
}, onCompleted: {
print("完成回調")
}, onDisposed: {
print("銷燬回調")
})
# 顯式調用 dispose
dispose.dispose()
複製代碼
這時候就會先調用 SinkDisposer
的dispose, 元祖 BinaryDisposable
你們還記得吧,SinkDisposer 會先調用,而銷燬者2
onDisposed 後調用
因此打印爲 序列dispose -> Disposables 釋放 -> 銷燬回調
Q 4 都有了 Q 5 還會遠嗎?
Q 5:
爲何調用了 dispose 就能夠銷燬 響應了呢?
由於 咱們銷燬了 Sink
,銷燬了大廈,銷燬了通訊管道,銷燬了外賣小哥送外賣的地址
還怎麼響應呢 ?
固然了,序列 和 觀察者
,終究是 iOS 裏面的 平凡的實例對象
,會隨着控制器的生命週期而銷燬
聽到這裏
懂了的扣 1
不懂的扣腳
RxSwift 還有一種垃圾回收方式, DisposeBag 能夠稱之爲 垃圾袋
能夠把它想象成 一個 autoReleasePool
裏面裝滿了銷燬者
隨着你把 DisposeBag 扔進垃圾桶,也就是控制器的生命週期
結束
裏面的銷燬者也就逐一銷燬
rx.disposeBag
由於 NSObject+Rx
對 垃圾袋 進行了優雅的拓展 ,咱們不須要本身建立 disposeBag 了
viewModel.title.asDriver()
.drive(titleLabel.rx.text)
.disposed(by: rx.disposeBag)
# 只需調用 rx.disposeBa 便可
# pod 'NSObject+Rx', '~> 5.0' # https://github.com/RxSwiftCommunity/NSObject-Rx
複製代碼
感興趣的能夠本身看一下 rx.disposeBag 的源碼
以上是我對 DisposeBag 的理解,還請不吝指正
但願你喝完這 2杯 mojito
味道的 RxSwift 以後
再也不須要垃圾袋