1. Disposables and DisposeBags?

我相信你知道,Disposables 和 DisposeBags 是RxSwift对Swift的ARC内存管理的让步。

当你订阅(subscribe)、绑定(bind)或驱动(drive)RxSwift Observable时,该订阅返回一个Disposable。这个Disposable对象基本上是对该订阅和该订阅的整个Observable chain 的引用。

在该disposable对象被释放之前,订阅链存在(除非订阅收到一个completed 或error事件,但那是另一回事)。

所以。底线是,subscriptions 返回 disposables,为了正确地控制订阅的生命周期,我们需要持有它。

为了方便起见,这些disposables通常被插入到一个被创建并附加到UIViewController(或在某些情况下附加到一个视图模型或其他对象)的DisposeBag中。

DisposeBag就是字面意思,一个装废弃物品的袋子(或集合)。

这对我们有什么帮助呢?

当视图控制器被释放时,它的变量(包括袋子)也被释放。当disposeBag被释放时,它的deinit函数会对它包含的所有disposable对象调用dispose。

这些disposables,会释放它们对所有可观测对象的引用,这些可观测对象也会释放它们对可观测对象的引用,如此循环下去,直到我们完成。

一切都被妥善释放,没有泄露,大家都很高兴。

除了一个小问题

1.1. Redundancy

那么,让我们假设你正在使用RxSwift,并且你正在使用MVVM(模型-视图-视图模型)架构。

在这个特定的屏幕上,我们的视图模型公开了一组可观察对象,我们的视图控制器将这些可观察对象绑定到一组标签。非常基础的东西。 代码是这样的。

class MVVMViewController: UIViewController {
    @IBOutlet weak var firstNameLabel: UILabel!
    @IBOutlet weak var lastNameLabel: UILabel!
    @IBOutlet weak var addressLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var stateLabel: UILabel!
    @IBOutlet weak var zipLabel: UILabel!
    private var viewModel = MyViewModel()
    private var disposeBag = DisposeBag()
    func setupSubscriptions() {
        viewModel.firstName
            .bind(to: firstNameLabel.rx.text)
            .disposed(by: disposeBag)
        viewModel.lastName
                .bind(to: lastNameLabel.rx.text)
                .disposed(by: disposeBag)
        viewModel.address
                .bind(to: addressLabel.rx.text)
                .disposed(by: disposeBag)
        viewModel.city
                .bind(to: cityLabel.rx.text)
                .disposed(by: disposeBag)
        viewModel.state
                .bind(to: stateLabel.rx.text)
                .disposed(by: disposeBag)
        viewModel.zip
                .bind(to: zipLabel.rx.text)
                .disposed(by: disposeBag)
    }
}

这些都非常简单,但是您可能已经注意到上面示例中有一点冗余的样板代码? 这是正确的。每一个订阅(绑定)都返回一个必须添加到disposeBag的一次性文件。每个人都返回它。每一个都要维护。这是无法回避的。

Or is there?

1.2. Solution? The Variadic DisposeBag

Now check out the following code.

class RxSwiftViewController: UIViewController {
    @IBOutlet weak var firstNameLabel: UILabel!
    @IBOutlet weak var lastNameLabel: UILabel!
    @IBOutlet weak var addressLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var stateLabel: UILabel!
    @IBOutlet weak var zipLabel: UILabel!
    private var viewModel = MyViewModel()
    private var disposeBag = DisposeBag()
    func setupSubscriptions() {
        disposeBag.insert(
            viewModel.firstName.bind(to: firstNameLabel.rx.text),
            viewModel.lastName.bind(to: lastNameLabel.rx.text),
            viewModel.address.bind(to: addressLabel.rx.text),
            viewModel.city.bind(to: cityLabel.rx.text),
            viewModel.state.bind(to: stateLabel.rx.text),
            viewModel.zip.bind(to: zipLabel.rx.text)
        )
    }
}

多干净!但是那些一次性的呢? RxSwift 4.3增加了一个可变版本的DisposeBag的插入函数。可变函数可以有一个或多个参数。在这种情况下是一个或多个一次性物品。

因为如果你查看dispose (by: disposeBag)内部,你会发现只有一行代码:disposeBag.insert(self)。

因此,我们不需要获取每个订阅的结果并将其函数式地链接到dispose(by:),而是绕过中间人,直接将它们添加到disposeBag中。

我认为您会同意代码绝对更简洁,并且通过消除一些样板文件,我们可以更好地表达函数的意图。