【问题标题】:Is calling `disposed(by:)` necessary in any case?在任何情况下都需要调用 `disposed(by:)` 吗?
【发布时间】:2020-09-04 19:34:46
【问题描述】:

作为标题,无论如何都需要调用disposed(by:)吗?如果是,为什么?

考虑一个像这样的简单示例:

class ViewController: UIViewController {
  let button = UIButton()

  override func viewDidLoad() {
    button.rx.tap.bind(onNext: { _ in
      print("Button tapped!")
    })
    // Does this make any retain cycle here?
  }
}

【问题讨论】:

  • 是的,例如当你希望监听器在创建控制器被销毁时也被销毁
  • 是的,只是因为当你查看控制器会被释放,那么disposebag会被释放,内存会被清理,也不会形成retain循环。
  • 但在上面的简单示例中,您不需要 DisposeBag。当视图控制器被释放时,订阅被释放。
  • 使用 DisposeBag 是一种很好的做法,但并不总是必要的。还有其他方法可以处理订阅,例如 takeUntil。你可以阅读更多here
  • @FabioFelici 是的。并且按钮tap 序列在内部使用takeUntil。这就是为什么我上面的例子很好。

标签: swift rx-swift


【解决方案1】:

不,不必每次都调用.disposed(by:)

如果你有一个 Observable 并且你知道它最终会发送一个停止事件,并且你知道你想继续监听这个 observable 直到它这样做,那么没有理由/不需要处理订阅,因此不需要将一次性用品放入一次性袋中。


.subscribe 及其同类返回 Disposable 的原因是调用代码可以在 observable 完成之前结束订阅。调用代码通过在返回的一次性对象上调用dispose() 来结束订阅。否则,订阅将继续,直到源 observable 发送停止事件(完成或错误)。

如果调用代码没有处理订阅,并且源 observable 没有发送停止事件,那么订阅将继续操作即使所有其他涉及的代码都丢失了对所涉及对象的所有引用在订阅中。

例如,如果你把它放在 viewDidLoad 中:

_ = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .subscribe(onNext: { print($0) })

上面的代码将在创建它的视图控制器不存在很久之后继续打印值。

在您提供的示例中,UIButton 对象在被取消初始化时发出一个完成事件,因此如果您想在发生这种情况之前一直监听按钮,请将可处置对象放入 dispose不需要包。

忽略disposables意味着你需要非常清楚哪些Observables是完整的,哪些是不完整的,但是如果你有这样的理解,你可以忽略它们。请记住,下一个开发人员,或者未来的你,不会像你那样对代码有很好的理解。

【讨论】:

  • 我 100% 同意你的看法。而且我刚刚意识到tap 序列在内部使用takeUntil,这就是为什么当按钮消失时资源将被释放的原因。我认为有很多人知道他们应该使用disposed(by),但并不真正了解其背后的原因。非常感谢您提供如此详细的答案。
猜你喜欢
  • 2010-10-07
  • 1970-01-01
  • 2022-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-06
相关资源
最近更新 更多