sequence
Previous article Mojito: RxSwift for my love, please
There is no mention of DisposeBag recycling
There are two reasons
Because of
Time was too short for me to see it
The second is because
Article too long, will be oral ulcer
Disposable
Don’t say a word. They’re all repeat visitors
Look at the classic case
let obable = Observable<String>.create { observer -> Disposable in
observer.onNext("dispose") # step1
observer.onCompleted() # step2
return Disposables.create {
print("Disposables release") # step6
}
}
_ = obable.subscribe(onNext: { (str) in
print("Sequence" + str) # step3
}, onError: { _ in
}, onCompleted: {
print("Complete callback") # step4
}, onDisposed: {
print("Destroy callback") # step5}) // Print sequence dispose -> Complete callback -> Destroy callback -> DisposablesCopy the code
Q1: Why is the closure return value of Disposable when the subscription is created?
Let’s get some ideas straight
Disposable
Dispose is an important method called dispose
public protocol Disposable {
# Deal with recycled resources.
func dispose()
}
Copy the code
Disposables
# Disposables is a structure
public struct Disposables {
private init() {}}# Disposables Extend create, return the value AnonymousDisposable
# Destroyer 1
extension Disposables {
public static func create(with dispose: @escaping () -> Void) -> Cancelable {
return AnonymousDisposable(disposeAction: dispose)
}
}
Copy the code
Disposables. Create, you have created the AnonymousDisposable, and pass in closure step6
The return value is of type Cancelable
A protocol named Cancelable that inherits Disposable
public protocol Cancelable : Disposable {
Has the resource been destroyed?
var isDisposed: Bool { get }
}
Copy the code
Let’s look at AnonymousDisposable
# Inherit DisposeBase and Cancelable, and have isDisposed & Dispose ()
private final class AnonymousDisposable : DisposeBase, Cancelable {
# Disposables. Create The closure you created
public typealias DisposeAction = () -> Void
private let _isDisposed = AtomicInt(0)
private var _disposeAction: DisposeAction?
Is it destroyed
public var isDisposed: Bool {
return isFlagSet(self._isDisposed, 1)
}
Save the closure
private init(_ disposeAction: @escaping DisposeAction) {
self._disposeAction = disposeAction
super.init()
}
Core methods are private for your own use only
fileprivate func dispose() {
if fetchOr(self._isDisposed, 1) == 0 {
if let action = self._disposeAction {
self._disposeAction = nil
action()
}
}
}
}
Copy the code
AtomicInt(0) : inherits NSLock and assigns the original value to 0
FetchOr and isFlagSet are methods of the AtomicInt class and are thread-safe
IsFlagSet:
func isFlagSet(_ this: AtomicInt, _ mask: Int32) -> Bool {
return (load(this) & mask) != 0
}
When self._isDisposed is not 0, they are disposed
# isFlagSet returns true, isFlagSet isDisposed to true
Copy the code
FetchOr:
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
this.lock()
let oldValue = this.value
this.value |= mask
this.unlock()
return oldValue
}
# | for operation, only when the zero for the first time, return oldValue 0
# External equation holds
# newValue is the value 1 after the bit operation, so the next equation will not equal 0
# Purpose: Destroy only once
Copy the code
dispose()
if let action = self._disposeAction {
self._disposeAction = nil
action()
}
The temporary action variable holds the external closure
Set external closure to nil
Execute closure
Copy the code
So here’s the summary
- summary
Disposables.create
是_subscribeHandler
When the closure executes the callback- When you perform
_subscribeHandler
An anonymous destroyer must be createdAnonymousDisposable
AnonymousDisposable
Instance, holding outsideDestruction of closure
AnonymousDisposable
, has theThe ability to destroy and only destroy once
, as well asWhether to destroy
The judgment of the
The destruction chain is as follows:
Disposables
This raises a second question
Q2: When is Dispose called?
Time goes back to subscribe
public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
-> Disposable {
let disposable: Disposable
# Prompt the world into an onDisposed closure, print(" Dispose callback ")
# Create AnonymousDisposable instance
if let disposed = onDisposed {
disposable = Disposables.create(with: disposed)
} else {
disposable = Disposables.create()
}
let observer = AnonymousObserver<Element> { event inswitch event { ... omitcase .error(let error):
disposable.dispose()
case .completed:
disposable.dispose()
}
}
# Return to the Disposables. Create
return Disposables.create(
self.asObservable().subscribe(observer),
disposable # Destructor 2 onDisposed)}Copy the code
So you can see that when the world calls subscribe, they pass in the onDisposed closure
The return value of SUBSCRIBE is also of type Disposable, which is also returned through Disposables. Create
You have a look at
This Disposables. Create, it has two parameters
Something strange happened
Point in
extension Disposables {
Create a new destroyer from 2 destroyers
public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable {
return BinaryDisposable(disposable1, disposable2)
}
}
Copy the code
Not for the sake of a father, but your family grave might be gone today
Said Disposables. Creat Disposables
BinaryDisposable destroyers, just like AnonymousDisposable, so I’m not going to do it here
private final class BinaryDisposable : DisposeBase, Cancelable {
....
# add one more parameter inside
var isDisposed: Bool {
return isFlagSet(self._isDisposed, 1)
}
func dispose() {
iffetchOr(self._isDisposed, 1) == 0 { self._disposable1? .dispose() self._disposable2? .dispose() self._disposable1 = nil self._disposable2 = nil } } }Copy the code
The problem comes to the binary destructor’s first argument self.asObservable().subscribe(observer)
It can be found in Producer
override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
# Pipe cleaner
# Return to a Disposer instance, and as it dissolves, release all references in the pipeline
let disposer = SinkDisposer()
Pass Disposer and subscriber to the run sequence AnonymousObservable
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
}
Copy the code
A pipeline cleaner SinkDisposer instance Disposer is created to hold the generated sink and subscription separately by calling run of AnonymousObservable
And return the disposer
In the AnonymousObservable
final private class AnonymousObservable<Element>: Producer<Element> {
override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
Generate an anonymous watch channel through the destroyers passed in above, and subscribers
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
The run call, which executes the _subscribeHandler closure, assigns the returned value to the subscription
# Subscription refers to destroyer 1
let subscription = sink.run(self)
return (sink: sink, subscription: subscription)
}
}
Copy the code
AnonymousObservableSink inherits from Sink, which also inherits from Disposable, representing that AnonymousObservableSink also has the ability of Dispose ()
Teacher, I feel dizzy
Can I have the DisposeBag first
I spit
Q3: What is the relationship between AnonymousObservableSink and SinkDisposer?
A 3: SinkDisposer will pass its instance to the channel AnonymousObservableSink by anonymous observation sequence, and channel Sink has the final interpretation right
It means that when the outside world executes its subscribe, it will creat a Disposables
Disposables contains:
- OnDisposed disposer 2
- Plumbing cleaner SinkDisposer
- sink
- AnonymousObservableSink
- subscription
- Destruction of 1
- sink
Because of the addition of the concept of Sink, Sink, as a translator, handles the relationship between the sequence and subscribers and destroyers
If you compare Sink to a building
SinkDisposer is the cleaner of the building, SinkDisposer is responsible to dispose of all disposables of the building, but the power of dispatching and interpretation belongs to Sink
SinkDisposer
private final class SinkDisposer: Cancelable {
private enum DisposeState: Int32 {
case disposed = 1
case sinkAndSubscriptionSet = 2
}
The initial value is 0
private let _state = AtomicInt(0)
private var _sink: Disposable?
private var _subscription: Disposable?
Set setSinkAndSubscription
func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
self._sink = sink
self._subscription = subscription
# 0 | 2, for the first time to return to oldValue 0, previousState is 0
# _state is assigned to 2
let previousState = fetchOr(self._state, DisposeState.sinkAndSubscriptionSet.rawValue)
# first previousState = 0, 0 & 2 = 0, continue
if(previousState & DisposeState.sinkAndSubscriptionSet.rawValue) ! = 0 { rxFatalError("Sink and subscription were already set")}# 0 & 1 = 0, not if
if(previousState & DisposeState.disposed.rawValue) ! = 0 { sink.dispose() subscription.dispose() self._sink = nil self._subscription = nil } }The above method has already been used once
func dispose() {
# after the first call setSinkAndSubscription _state to 2, 2 | 1 = 3, fetchOr returns the old value 2, _state into 3
# previousState is 2
let previousState = fetchOr(self._state, DisposeState.disposed.rawValue)
# 2&1 = 0, do not enter if, continue walking
if(previousState & DisposeState.disposed.rawValue) ! = 0 {return
}
# 2&2 = 2, dispose, if is satisfied, respectively
if(previousState & DisposeState.sinkAndSubscriptionSet.rawValue) ! = 0 {Dispose is called # AnonymousObservableSink
sink.dispose()
Dispose is called
subscription.dispose()
After destruction, set nil respectively
self._sink = nil
self._subscription = nil
}
}
}
Copy the code
Q A
Q1: Why is the closure return value of Disposable when the subscription is created?
The Disposable type refers to the anonymous destructor, which is destructor 1. Because you want to dig a grave and erect a tombstone for the sequence when it’s created
As wild said
I bloom in slaughter like a flower in the dawn
Dying doesn’t matter. Being handsome is done
Q2: When is Dispose called?
In this article, onCompleted is explicitly called, which executes the SUBSCRIBE onCompleted closure and then calls
disposable.dispose()
case .completed:
onCompleted?()
disposable.dispose() # Destroyer 2
}
Copy the code
The print order is complete callback -> Destroy callback
The onCompleted signal must flow down the pipe to AnonymousObservableSink, calling sink’s ON, i.e
case .error, .completed:
if fetchOr(self._isStopped, 1) == 0 {
self.forwardOn(event)
self.dispose() Dispose of the parent class Sink, which calls SinkDisposer}}Copy the code
Then SinkDisposer will take care of Sink and disposer 1
So finally print Disposables 1’s closure -> Disposables
Execution order details
Here we derive Q 4: What if onCompleted is not explicitly called? Instead of
let obable = Observable<String>.create { observer -> Disposable in
observer.onNext("dispose")
// observer.onCompleted()
return Disposables.create {
print("Disposables release")}}let dispose = obable.subscribe(onNext: { (str) in
print("Sequence" + str)
}, onError: { _ in
print(Error callback)
}, onCompleted: {
print("Complete callback")
}, onDisposed: {
print("Destroy callback")})Dispose is explicitly called
dispose.dispose()
Copy the code
And then you’re going to call SinkDisposer’s dispose, primary BinaryDisposable you remember, SinkDisposer is going to disposer first, and disposer 2 onDisposed
So print the sequence dispose -> Disposables release -> Destroy callback
Q 4, Q 5 can be far behind?
Q 5: Why does Dispose dispose dispose the response?
Because we destroyed the Sink, the building, the communication pipeline and the address of the delivery boy
How do you respond?
Of course, sequences and observers, after all, are mundane instance objects in iOS that will be destroyed over the lifetime of the controller
I heard that
Deduct 1 if you understand
Do not understand the buckle foot
DisposeBag
RxSwift also has a garbage collection method, DisposeBag can be called garbage bag
Think of it as an autoReleasePool
It’s full of destroyers
As you throw the DisposeBag into the trash, the controller’s life cycle ends
The destroyers inside will be destroyed one by one
rx.disposeBag
Because NSObject+Rx is an elegant extension of garbage bags, we don’t need to create disposebags ourselves
viewModel.title.asDriver()
.drive(titleLabel.rx.text)
.disposed(by: rx.disposeBag)
Just call rx.disposeba
# pod 'NSObject + Rx', '~ > 5.0 # https://github.com/RxSwiftCommunity/NSObject-Rx
Copy the code
If you are interested, take a look at the source code for Rx. disposeBag
After the
Above is my understanding of DisposeBag, please do not hesitate to correct
Hopefully after you finish these two mojito flavored RxSwift
No more trash bags