about sequence
先引用下官方文档:
Here is a sequence of numbers:
--1--2--3--4--5--6--| // terminates normally
Another sequence, with characters:
--a--b--a--a--a---d---X // terminates with error
Some sequences are finite while others are infinite, like a sequence of button taps:
---tap-tap-------tap--->
序列从生命周期来讲分为两种: 有限序列和无限序列, 有限序列以complete或者error结束,而无限序列永远都不会发送complete或者error事件。
首先明确一点观察者的生命周期肯定是要比被观察者的生命周期要长的,不然怎么观察呢,如果观察者都死掉了,被观察者还在干活,那你怎么观察呢?
对于有限序列还比较好办,在序列结束的时候发个通知告诉观察者就可以了罗。
对于无限序列呢?怎么去管理它的生命周期呢?既要保证观察者的生命周期比被观察者长,又要在恰当的时候销毁掉它。
有限序列
// AnonymousObservableSink.on
func on(_ event: Event) {
#if DEBUG
_synchronizationTracker.register(synchronizationErrorMessage: .default)
defer { _synchronizationTracker.unregister() }
#endif
switch event {
case .next:
if _isStopped == 1 {
return
}
forwardOn(event)
case .error, .completed:
if AtomicCompareAndSwap(0, 1, &_isStopped) {
forwardOn(event)
dispose()
}
}
}
有限序列在onError或者onComplete的时候,触发dispose操作。
无限序列
无限序列就比较麻烦了,先分析下类的归属问题
// Producer.subscribe
let disposer = SinkDisposer()
let sinkAndSubscription = run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
// AnonymousObservable.run
override func run(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element {
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
let subscription = sink.run(self)
return (sink: sink, subscription: subscription)
}
SinkDisposer 持有 Sink 和 Subscription
AnonymousObservableSink持有 SinkDisposer 和 Observer
看上去有点不太理解,没关系对应下面这个具体例子:
Observable.create { observer -> Disposable in
observer.onNext("hello")
return Disposables.create()
}
.subscribe { event in
print(event.element)
}
SinkDisposer 持有 AnonymousObservableSink 和
{ observer -> Disposable in
observer.onNext("hello")
return Disposables.create()
}
闭包产生的Disposable
AnonymousObservableSink: 持有 SinkDisposer 和
.subscribe { event in
print(event.element)
}
闭包产生的AnonymousObserver.
这样的话Sink持有SinkDisposer, SinkDisposer又持有Sink形成闭环,循环引用下内存永远不会释放。
验证设想
有限序列
func testObservable() {
Observable.create { observer -> Disposable in
observer.onNext("hello")
observer.onCompleted()
return Disposables.create()
}
.debug()
.subscribe { event in
print(event.element)
}
defer {
print("testObservable end")
}
}
// output log
2018-09-20 15:05:18.695: AppDelegate.swift:134 (testObservable()) -> Event next(hello)
Optional("hello")
2018-09-20 15:05:18.696: AppDelegate.swift:134 (testObservable()) -> Event completed
nil
2018-09-20 15:05:18.696: AppDelegate.swift:134 (testObservable()) -> isDisposed
testObservable end
在Debug模式下会跟踪observable的事件信息和生命周期,这里可以看到在completed情况下,成功触发dispose
无限序列
func testObservable() {
Observable.create { observer -> Disposable in
observer.onNext("hello")
return Disposables.create()
}
.debug()
.subscribe { event in
print(event.element)
}
defer {
print("testObservable end")
}
}
2018-09-20 15:20:29.176: AppDelegate.swift:134 (testObservable()) -> subscribed
2018-09-20 15:20:29.177: AppDelegate.swift:134 (testObservable()) -> Event next(hello)
Optional("hello")
testObservable end
这里可以看到没有dispose,现在这种情况下已经造成内存泄漏,这块内存永远不会释放了。
这就是为什么官方推荐你使用下面这种写法的原因:
Observable.create { observer -> Disposable in
observer.onNext("hello")
// observer.onCompleted()
return Disposables.create()
}
.debug()
.subscribe { event in
print(event.element)
}
.disposed(by: disposeBag)
通过DisposeBag管理观察者的生命的周期,DisposeBag使用数组存放Disposable,在被释放前,会调用所有Disposable.dispose操作,达到释放内存的目的。再来看看dispose具体干了些啥:
// SinkDisposer.dispose
func dispose() {
let previousState = AtomicOr(DisposeState.disposed.rawValue, &_state)
if (previousState & DisposeStateInt32.disposed.rawValue) != 0 {
return
}
if (previousState & DisposeStateInt32.sinkAndSubscriptionSet.rawValue) != 0 {
guard let sink = _sink else {
rxFatalError("Sink not set")
}
guard let subscription = _subscription else {
rxFatalError("Subscription not set")
}
sink.dispose()
subscription.dispose()
_sink = nil
_subscription = nil
}
}
首先SinkDisposer 会调用 sink.dispose()
subscription.dispose()
紧接着将其置空,置空之后这个引用环就解开了,自然对象就会被释放掉。
结论
在任何时候使用subscribe
都必须将其加入到DisposeBag
中,否则就有可能造成内存泄漏,这样还带来一个好处你无需关注序列到底是有限序列还是无限序列,反正内存会最终释放。