我是从一篇博文中读到的 http://adamborek.com/memory-managment-rxswift/ :
When you subscribe for an
Observable
theDisposable
keeps a reference to theObservable
and theObservable
keeps a strong reference to theDisposable
(Rx creates some kind of a retain cycle here). Thanks to that if user navigates back in navigation stack theObservable
won’t be deallocated unless you want it to be deallocated.
所以纯粹为了理解这一点,我创建了这个虚拟项目:哪里有一个 View ,在 View 的中间,有一个巨大的按钮,它会发出关于按钮被点击多少次的事件。就那么简单。
import UIKit
import RxCocoa
import RxSwift
class Button: UIButton {
private var number: Int = 0
private let buttonPushedSubject: PublishSubject<Int> = PublishSubject.init()
var buttonPushedObservable: Observable<Int> { return buttonPushedSubject }
deinit {
print("Button was deallocated.")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
@objc final func buttonTapped() {
number = number + 1
buttonPushedSubject.onNext(number)
}
}
class ViewController: UIViewController {
@IBOutlet private weak var button: Button!
deinit {
print("ViewController was deallocated.")
}
override func viewDidLoad() {
super.viewDidLoad()
button.buttonPushedObservable.subscribe(onNext: { (number) in
print("Number is \(number)")
}, onError: nil, onCompleted: nil, onDisposed: nil)
}
}
令人惊讶的是,在我关闭这个 View Controller 之后,日志看起来像这样:
Number is 1
Number is 2
Number is 3
Number is 4
ViewController was deallocated.
Button was deallocated.
...
这意味着 ViewController
和 Button
都已发布!在这种情况下,我没有调用 disposeBy(bag)
并且编译器发出警告。
然后我开始看subscribe(onNext:...)
的实现(下c/p):
let disposable: Disposable
if let disposed = onDisposed {
disposable = Disposables.create(with: disposed)
}
else {
disposable = Disposables.create()
}
let callStack = Hooks.recordCallStackOnError ? Hooks.customCaptureSubscriptionCallstack() : []
let observer = AnonymousObserver<E> { event in
switch event {
case .next(let value):
onNext?(value)
case .error(let error):
if let onError = onError {
onError(error)
}
else {
Hooks.defaultErrorHandler(callStack, error)
}
disposable.dispose()
case .completed:
onCompleted?()
disposable.dispose()
}
}
return Disposables.create(
self.asObservable().subscribe(observer),
disposable
)
在上面的代码块中,observer
确实通过 lambda 函数持有对 disposable
的强引用。但是,我不明白的是,disposable
是如何对 observer
进行强引用的?
最佳答案
虽然 observable 处于事件状态,但存在一个引用循环,但是按钮的释放会发送一个完整的事件,从而打破循环。
就是说,如果你做这样的事情 Observable<Int>.interval(3).subscribe()
流将不会解除分配。
如果源完成/错误或者如果对生成的可释放对象调用 dispose(),Streams 只会关闭(并因此解除分配)。使用上面的代码行,源 ( interval
) 将永远不会完成或出错,并且不会保留对一次性对象的引用,因此无法对其调用 dispose()。
最好的思考方式是……complete
/error
是源告诉接收器它已完成发射(这意味着不再需要流)并调用 dispose()
的方式。 on the disposable 是 sink 告诉源它不想再接收任何事件的方式(这也意味着不再需要流。)为了释放流,源或接收器需要报告完成了。
要明确回答您的问题...您不需要将一次性元素添加到处置袋中,但是如果 View Controller 在没有处置的情况下删除并且源不发送完整的消息,流将泄漏。所以安全第一,确保水槽在处理完流后进行处置。
关于rx-swift - 为什么我们需要在 RxSwift 中在 "disposeBy(bag)"之后显式调用 "subscribe",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52843198/