Disposable-可被清除的资源

通常来说,一个序列如果发出了error或者completed事件,那么所有内部资源都会被释放。如果你需要提前释放这些资源或取消订阅的话,那么你可以对返回可被清除的资源(Disposable)调用dispose方法:

var disposable: Disposable?

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    self.disposable = textField.rx.text.orEmpty
        .subscribe(onNext: { text in print(text) })
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.disposable?.dispose()
}

调用dispose方法后,订阅将被取消,并且内部资源都会被释放。通常情况下,你是不需要手动调用dispose方法的,这里只是做个演示而已。我们推荐使用清除包(DisposeBag)或者takeUntil操作符来管理订阅的生命周期。


DisposeBag-清除包

因为我们用的是Swift,所以我们更习惯于使用ARC来管理内存。那么我们能不能用ARC来管理订阅的生命周期呢。答案是肯定的,你可以用清除包(DisposeBag)来实现这种订阅管理机制:

let disposeBag = DisposeBag()

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    textField.rx.text.orEmpty
        .subscribe(onNext: { text in print(text) })
        .disposed(by: self.disposeBag)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.disposeBag = DisposeBag()
}

清除包被释放的时候,清除包内部所有可被清除的资源(Disposable)都将被清除。

let 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)

    passwordValid
        .bind(to: passwordValidOutlet.rx.isHidden)
        .disposed(by: disposeBag)

    everythingValid
        .bind(to: doSomethingOutlet.rx.isEnabled)
        .disposed(by: disposeBag)

    doSomethingOutlet.rx.tap
        .subscribe(onNext: { [weak self] in self?.showAlert() })
        .disposed(by: disposeBag)
}

这个例子中disposeBagViewController具有相同的生命周期。当退出页面时,ViewController就被释放,disposeBag

也跟着被释放了,那么这里的5次绑定(订阅)也就被取消了。这正是我们所需要的。


takeUntil

另外一种实现自动取消订阅的方法就是使用takeUntil操作符,上面那个输入验证的演示代码也可以通过使用takeUntil来实现:

override func viewDidLoad() {
    super.viewDidLoad()

    ...

    _ = usernameValid
        .takeUntil(self.rx.deallocated)
        .bind(to: passwordOutlet.rx.isEnabled)

    _ = usernameValid
        .takeUntil(self.rx.deallocated)
        .bind(to: usernameValidOutlet.rx.isHidden)

    _ = passwordValid
        .takeUntil(self.rx.deallocated)
        .bind(to: passwordValidOutlet.rx.isHidden)

    _ = everythingValid
        .takeUntil(self.rx.deallocated)
        .bind(to: doSomethingOutlet.rx.isEnabled)

    _ = doSomethingOutlet.rx.tap
        .takeUntil(self.rx.deallocated)
        .subscribe(onNext: { [weak self] in self?.showAlert() })
}

这将使得订阅一直持续到控制器的dealloc事件产生为止。

results matching ""

    No results matching ""