RxSwift 是一個很好用的第三方套件,而他因為支援比較低的 iOS 版本,所以也是目前海芋有用到的第三方 Reactive 開發套件,而我們有時必須將我們已訂閱的 Observable 取消訂閱,這時就可以使用 takeUntil 啦,這可是使用 RxSwift 必學的絕招!
![[RxSwift] 利用 takeUntil 來取消訂閱 1 swift 1](https://www.inote.tw/wp-content/uploads/2020/02/swift-1.png)
takeUntil 最神奇的地方是在會同時監聽兩個 Observable,當第二個 Observable 發出時,就會停止原本的 Observable。舉一個官方的簡單例子來說。
let disposeBag = DisposeBag()
let aObservable = PublishSubject<String>()
let bObservable = PublishSubject<Void>()
aObservable
.take(util: bObservable)
.subscribe { print($0) }
.disposed(by: disposeBag)
aObservable.onNext("Hello")
aObservable.onNext("World")
bObservable.onNext(())
// 底下不會印出來
aObservable.onNext("Not Print")
這個原理就是他同時觀察「aObservable」和「bObservable」,因為「bObservable」已經觸發了,所以aObservable就被取消訂閱了。
再舉一個最簡單的例來說,我們可能 ViewController 內監聽進入前景和背景,來不同的事件 (文:如何利用 RxSwift 監聽進入背景/前景),我們可能的寫法可能會寫成這樣。
class ExampleController: UIViewController{
lazy var disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default
.rx.notification(UIApplication.didEnterBackgroundNotification)
.subscribe(onNext: { _ in
//進入背景
}).disposed(by: disposeBag)
NotificationCenter.default
.rx.notification(UIApplication.willEnterForegroundNotification)
.subscribe(onNext: { _ in
//進入前景
}).disposed(by: disposeBag)
}
}
這樣的寫法在大多數底下都不會有問題,但如果是使用 JXSegmentedView 這類的套件來建立 Paging,這樣的寫法就可能產生問題了,因為 JXSegmentedView 的寫法讓你可以同時存在許多 UIViewController,所以我的思路是,那就畫面出現時來監聽,消失時取消監聽,所以必須改寫成在畫面 viewDidAppear 再來監聽,並在 viewWillDisappear 取消監聽,也因此改寫如下即可。
class ExampleController: UIViewController{
lazy var disposeBag = DisposeBag()
lazy var cancellingObservable = PublishSubject<Void>()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
cancellingObservable.onNext(())
NotificationCenter.default
.rx.notification(UIApplication.didEnterBackgroundNotification)
.take(util: cancellingObservable)
.subscribe(onNext: { _ in
//進入背景
}).disposed(by: disposeBag)
NotificationCenter.default
.rx.notification(UIApplication.willEnterForegroundNotification)
.take(util: cancellingObservable)
.subscribe(onNext: { _ in
//進入前景
}).disposed(by: disposeBag)
}
override func viewWillDisappear() {
super.viewWillDisappear()
cancellingObservable.onNext(())
}
}
其中在 viewDidAppear 和 viewWillDisappear 分別觸發一次 cancellingObservable 來取消訂閱,來確保程式進入背景或前景時,只會被訂閱一次,並在畫面消失時取消訂閱。takeUntil 真的是 RxSwift 中一個非常實用的 Operator,你一定要學會他喔!