Click here to share learning with 2000+ iOS developers
RxSwift Core Process
RxSwift is an excellent framework, and its api is also very streamlined, so that unfamiliar users can get started very quickly.
- 1: Create Sequences
- 2: Subscription Sequence
- 3: Send Signals
// 1: Create Sequences _ = Observable<String>.create { (obserber) -> Disposable in // 3: Send Signals obserber.onNext("Cooci - Frame Class") return Disposables.create() // This destruction does not affect our interpretation this time. // 2: Subscription Sequence }.subscribe(onNext: { (text) in print("Subscribe to:\(text)") }) // Console Printing: "Subscribe to: Cooci - Framework Class"
When I started exploring, I was curious about why this string would print in the closure of subscribe in the subscribe sequence. Here's my code analysis
Analysis code:
- 1: Create a sequence of code behind closure A, which contains 3: Send a signal, if you want to execute a signal, you must come to this closure A.
- 2: We executed 2: Subscription Sequence to create Closure B
- 3: From the results, we clearly know that closure A is implemented first and Cooci - Framework class is passed on to closure B.
- Guess: Closure execution calls are nested in the code! We begin to interpret the source code to verify the authenticity of the guess.
RxSwift Core Logic
Create Sequences
extension ObservableType { // MARK: create public static func create(_ subscribe: @escaping (AnyObserver<E>) -> Disposable) -> Observable<E> { return AnonymousObservable(subscribe) } }
You can see clearly that our creation of observable sequence is realized by using the creation method of protocol extension function. Whether it create s an Anonymous Observable (anonymous observable sequence) name or reflects the author's thinking: this class is an internal class with some general features (self-contained). I will post the inheritance relationship of this class.
From the above figure, we can clearly see the inheritance relationship. So much content and so many layers of nesting, what do we need to grasp in this place?
- When creating a method, an internal object is create d.
- Anonymous Observable saves external closures
- Anonymous Observable inherits Producer's very important method, subscribe
Subscription sequence
Here we show that this subscribe method is not the same as the subscribe method we mentioned above.
From the extended function of ObservableType
extension ObservableType { public func subscribe(onNext: ((E) -> Void)? = nil, ...) -> Disposable { // Because space omission does not affect the code we explore 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 ) } }
Code description:
- E. This means Swift's Association type. If you look carefully at the source code of the inheritance chain of observable sequences, it should be easy to get: This E is our sequence type, and here we are String.
public class Observable<Element> : ObservableType { /// Type of elements in sequence. public typealias E = Element
- Create an Anonymous Observer (anonymous internal observer) approach similar to our Anonymous Observable, where initialization is a closure parameter, preserving external onNext, onError, onCompleted, onDisposed callbacks to handle callbacks closures, and I'll post the inheritance of the observer. Chain relationship, help you understand
- self.asObservable() This is our RxSwift for consistency.
- The essence of self.asObservable().subscribe(observer) is actually self.subscribe(observer). Through observable sequence inheritance, we can locate the Producer subscription code very quickly.
override func subscribe(_ observer: O) -> Disposable where O.E == Element { if !CurrentThreadScheduler.isScheduleRequired { // For space reasons, we omit some code to facilitate our understanding. ... return disposer } else { return CurrentThreadScheduler.instance.schedule(()) { _ in let disposer = SinkDisposer() let sinkAndSubscription = self.run(observer, cancel: disposer) // For space reasons, we omit some code to facilitate our understanding. ... return disposer } } }
- The destruction code and dispatcher code are not analyzed here.
- self.run is the code that eventually extends from our producer Producer to our specific transaction code, Anonymous Observable.run.
override func run (...) { let sink = AnonymousObservableSink(observer: observer, cancel: cancel) let subscription = sink.run(self) return (sink: sink, subscription: subscription) }
- Sik. run is also better written, business processing is sinking, so that the division of labor is more clear.
func run(_ parent: Parent) -> Disposable { return parent._subscribeHandler(AnyObserver(self)) }
- parent is the nonymousObservable object passed from above
- We were very excited to see Anonymous Observable. _subscribeHandler, from which we wondered why our sequence subscription process would execute our sequence closure and then send a response.
- The code that sends the response will be analyzed later. Here's another important guy, AnyObserver(self)
public init<O : ObserverType>(_ observer: O) where O.E == Element { self.observer = observer.on }
- In this constructor, we create a structure, AnyObserver, which stores a message. The Anonymous ObservableSink. on function, not Anonymous ObservableSink, is a place where people who first come here make mistakes. I wonder if you realize it!
Send response
From the above analysis, it is very clear that:
The essence of obserber.onNext("Cooci-Frame Class") is: AnyObserver.onNext("Cooci-Frame Class").
It's normal to find out that our AnyObserver doesn't have this method. General Ideas, Find Parents, Find Protocols
extension ObserverType { public func onNext(_ element: E) { self.on(.next(element)) } }
- External obserber.onNext("Cooci-Frame Class") is transformed again: AnyObserver.on(.next("Cooci-Frame Class"), here you must be main, this AnyObserver calls the on function, which passes through the. next function with our final parameters.
public struct AnyObserver<Element> : ObserverType { public init<O : ObserverType>(_ observer: O) where O.E == Element { self.observer = observer.on } public func on(_ event: Event<Element>) { return self.observer(event) } }
- self.observer construction initialization is: Anonymous ObservableSink.on function
- Seeing this, we are going to change again: self. Observer - > Anonymous Observable Sink. on (event) where event = next (Cooci - Framework Class). Finally, our core logic goes back to the magic pipe of sink. We can't help but be amazed at this place. RxSwift's design ability and who else has it.~~~
class AnonymousObservableSink<O: ObserverType>: Sink<O>, ObserverType { func on(_ event: Event<E>) { switch event { case .next: if load(self._isStopped) == 1 { return } self.forwardOn(event) case .error, .completed: if fetchOr(self._isStopped, 1) == 0 { self.forwardOn(event) self.dispose() } } } }
- Self. forward On (event) is also the core code for execution, because Anonymous Observable Sink inherits Sink. There is also encapsulation here. See the code below.
class Sink<O : ObserverType> : Disposable { final func forwardOn(_ event: Event<O.E>) { if isFlagSet(self._disposed, 1) { return } self._observer.on(event) } }
- Where self._observer is our initially saved observer: Anonymous Observer
- So the essence of our metamorphosis is: Anonymous Observer. on (. next("Cooci - Framework Class"), my God! Here logic goes back to the call of the parameter closure created by Anonymous Observer when we subscribe to the sequence! Everything feels so verbose, but it's so natural.
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() } }
- Judge the event and then call onNext?(value) because the enumerated correlation value (Swift's powerful function) value = Cooci - Framework class, and then the external onNext closure call parameters, then the source code parses here, I believe you have fully grasped the core logic of RxSwift, and finally attached here. On our analytical diagrams
Summary: Structure of RxSwift
- 1: The sense of sequence is that the whole world is a unified sequence-coding, enjoying at any time and anywhere.
- 2: Use functional thinking to sink some columns of requirements operations (encapsulating things that developers don't care about) - optimize the code and save logic
- 3: The most typical feature of RxSwift is to solve the response ability of Swift, which is a static language. With the change of the time dimension sequence as the axis, user subscription care can keep alive along the axis, reaching subscription once, and the response lasts all the time.~