RxSwift 的資源管理

關於 RxSwift 的記憶體管理機制

在介紹關於 RxSwift 基本入門 中提到了一些 RxSwift 的核心概念 - Observable ,我們描述了事件訊息的種類,分別是 : nexterrorcompleted , 當這個 Observable 收到errorcompleted 事件訊息時,那麼這個 Observable 將不會再接受其他的訂閱事件。 同時在這邊用來分派給此 Observable 的記憶體資源就一起被釋放掉了,我們可以將其視為類似 ARC 的自動記憶體釋放。 如果你想立刻將 Observable 關閉且立刻釋放資源,那麼你需要呼叫 dispose 函數,這邊我們可以理解為類似 MRC 的手動釋放。

如果一個 Observable 在一定的時間內結束,即使不呼叫 dispose 或者使用 DisposeBag 也不會引發 Memory Leak。 如果一個 Observable 因為某些原因

沒有結束,那記憶體將會永遠的不會被釋放,所以就算 根據 Observable 的運作原理,我們也會希望透過某些記憶體回收機制來確保不會產生 Memory Leak 的問題。

下面將詳細介紹幾種 RxSwift 的記憶體管理機制。

Disposing

在一開始提到的,我們可以呼叫 dispose 方法,去直接關閉這個 Observable

下面是一個簡單的例子 :

1
2
3
4
5
6
7
let subscription = Observable<Int>.interval(0.3, scheduler: scheduler)
.subscribe { event in
print(event)
}

NSThread.sleep(forTimeInterval: 2.0)
subscription.dispose()

Result :

1
2
3
4
5
6
0
1
2
3
4
5

不過這並不是一個好方法,手動呼叫 dispose 是一種不太好的編程習慣。更好的方法是使用像是 DisposeBag 或者一些其他的機制。

如果在dispose 被執行之後,還會繼續執行 subscribe 中的代碼片段嗎 ? 像是在這個範例中,還會繼續 print 東西嗎 ? 答案是 : 不一定

要視 scheduler 被訂閱時所在的執行緒以及 dispose 呼叫的執行緒 而定。

如果 scheduler 是一個 serial scheduler ,例如 : MainScheduler 並且 dispose 在同一個 serial scheduler 被呼叫,答案是不會,否則答案是會的

關於 RxSwiftscheduler 我們會在後面做更詳細的討論,假如你真的需要呼叫 dispose ,那麼我們為了避免出現上述的狀況,我們必須詳細的告訴 Observable 訂閱的 scheduler 執行緒以及確保 dispose 呼叫的方法在同一執行緒。

1
2
3
4
5
6
7
8
9
10
//observeOn on MainScheduler(main thread)
let subscription = Observable<Int>.interval(0.3, scheduler: scheduler)
.observeOn(MainScheduler.instance)
.subscribe { event in
print(event)
}

// ....

subscription.dispose()// called from main thread

這樣就能確保在 dispose 之後不會在 print 出任何訊息了。

Dispose Bags

Dispose BagRxSwift 中的作用與 ARC 類似。它就像是一個 autoreleasepool 一樣。當 disposeBag 被銷毀時,同時銷毀被加入這個 disposeBagObservable

基本的 disposeBag 使用方法。

1
2
3
4
5
6
7
let disposeBag = DisposeBag()

Observable<Int>.empty()
.subscribe { event in
print(event)
}
.disposed(by: disposeBag)

disposeBagscope 結束時,就會呼叫解構子,當 Dispose Bag 的解構子被呼叫的時候,他會對每個 Observable 呼叫 dispose 方法。

如果你需要馬上清除記憶體,你可以立刻創建一個新的 DisposeBag

1
self.disposeBag = DisposeBag()

如果需要顯式的手動清理資源,那麼需要使用 CompositeDisposable

Take until

另外一種自動管理機制則是使用 takeUntil

1
2
3
4
5
sequence
.takeUntil(self.rx.deallocated)
.subscribe {
print($0)
}

以上就是關於 RxSwift 的記憶體管理機制。這次介紹就到這邊結束,希望能讓大家對於 RxSwift 有更深一步的認識。