[RxSwift] 利用 takeUntil 來取消訂閱

RxSwift 是一個很好用的第三方套件,而他因為支援比較低的 iOS 版本,所以也是目前海芋有用到的第三方 Reactive 開發套件,而我們有時必須將我們已訂閱的 Observable 取消訂閱,這時就可以使用 takeUntil 啦,這可是使用 RxSwift 必學的絕招!

swift 1

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,你一定要學會他喔!

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments