The original address: www.jianshu.com/p/0e0703466…

As one of the ReactiveX family of RxSwift on Github as of now Star:16K. Why is this framework so popular, and how is the underlying implementation implemented as the poster child for functional responsive frameworks? This article is fully declassified

RxSwift core process

RxSwift this excellent framework, the design of the API is very simplified, so that unfamiliar users can also be very fast

  • 1: Create a sequence
  • 2: Subscription sequence
  • 3: sends signals
Observable<String>. Create {(obserber) -> Disposablein// 3: send signal obserber.onnext ("Cooci - Frame Class")
    return// 2: Subscribe}. Subscribe (onNext: {(text)in
        print("Subscribe to :\(text)")}) // Console prints: "Subscribe to :Cooci - frame class"Copy the code

When I first started exploring, I was curious as to why the string in our Cooci-frame class was printed in the closure of the subscribe sequence. Here is my code analysis

Analysis code:

  • 1: code to create the sequenceCreateAt the back of theThe closure of AThere is a3: sends signalsIf it is to be executedSend a signalI have to come to thisThe closure of A
  • 2: We execute2: Subscription sequenceTo create theClosure B
  • 3: We clearly know from the results, execute firstThe closure of ACooci - Frame classPassed on toClosure B
  • Guess: there is a nested closure execution call inside the code! Guess the truth, we began to read the source code to verify

PS: To tell the truth, the source code of RxSwift framework is really more complex and a lot of, a lot of foundation is weak or impatient partners are easy to give up. But if you read this blog post, you’re in luck: I’ll give you a quick and brief introduction, with my mind map at the end!

RxSwift core logic

Create a sequence

extension ObservableType {
    // MARK: create
    public static func create(_ subscribe: @escaping (AnyObserver<E>) -> Disposable) -> Observable<E> {
        return AnonymousObservable(subscribe)
    }
}

Copy the code

You can clearly see that our observable sequence is created using the protocol extension create method, which creates an AnonymousObservable (AnonymousObservable sequence) named after the author: This class is an inner class with some common features (classes with their own functionality are named) and I post the inheritance of this class below

From the figure above, we can clearly see the inheritance relationship. So with so much content and so many layers of nesting, here’s what we need to know:

  • createMethod to create an internal objectAnonymousObservable
  • AnonymousObservableThe external closure is saved
  • AnonymousObservableinheritedProducerIt has a very important methodsubscribe

Subscribe to the sequence

Subscribe is not the same method as subscribe

From theObservableTypeExtended function of

extension ObservableType { public func subscribe(onNext: ((E) -> Void)? = nil, ...) -> Disposable {// because length omission does not affect the code we are exploringlet observer = AnonymousObserver<E> { event in                
                switch event {
                case .next(letvalue): 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
            )
    }
}

Copy the code

Code description:

  • EThe idea here is thatSwiftIf you take a close look at the source code of the inheritance chain of the observable sequence, it should not be difficult to conclude: thisEThat’s our sequence type, which we have hereString
public class Observable<Element> : ObservableType {
    /// Type of elements in sequence.
    public typealias E = Element

Copy the code
  • Created aAnonymousObserver (anonymous internal Observer)Techniques and oursAnonymousObservablePretty much, its initialization here is the closure parameter that holds the outsideonNext, onError , onCompleted , onDisposedHandles the call to the callback closure, which I’ll post for you belowThe observerTo help you understand

  • self.asObservable()This is oursRxSwiftJust to keep it consistent
  • self.asObservable().subscribe(observer)The essence is thatself.subscribe(observer)Through the inheritance relationship of observable sequence, we can locate very quicklyProducerThe subscription code
override func subscribe(_ observer: O) -> Disposable where O.E == Element {
        if! CurrentThreadScheduler. IsScheduleRequired {/ / space reasons, we omit some code, convenient we understand...return disposer
        }
        else {
            return CurrentThreadScheduler.instance.schedule(()) { _ in
                let disposer = SinkDisposer()
                letSinkAndSubscription = self.run(observer, cancel: Disposer) //return disposer
            }
        }
    }

Copy the code
  • The destruction code and scheduler code are not analyzed here
  • self.runThis code is ultimately produced by usProducerThis extends to our specific transaction codeAnonymousObservable.run
override func run (...) {
    let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
    let subscription = sink.run(self)
    return (sink: sink, subscription: subscription)
}

Copy the code
  • sink.runThe writing method is also better, business processing or sink, so that the division of labor is more clear
func run(_ parent: Parent) -> Disposable {
    return parent._subscribeHandler(AnyObserver(self))
}

Copy the code
  • parentIt was sent from aboveAnonymousObservableobject
  • We are very excited to seeAnonymousObservable._subscribeHandlerFrom this code we are puzzled why ourSequence of subscriptionThe process will execute usSequence of closure“And then executeSend a response
  • The code to send the response will be examined later, but there is one more important guyAnyObserver(self)
public init<O : ObserverType>(_ observer: O) where O.E == Element {
    self.observer = observer.on
}

Copy the code
  • In this constructor, we create a structureAnyObserverA message is savedAnonymousObservableSink. On function, notAnonymousObservableSinkIt’s a place where most first-time visitors make mistakes. I don’t know if you realize this!

Send a response

Our analysis from above is very clear:Obserber.onnext ("Cooci - Frame class ")The essence of:Anyobserver. onNext("Cooci - Frame class ")

At this time, we found that AnyObserver does not have this method, which is normal! General idea, find the parent class, find the protocol

extension ObserverType {
    public func onNext(_ element: E) {
        self.on(.next(element))
    }
}

Copy the code
  • The outside worldObserber.onnext ("Cooci - Frame class ")Deform again:Anyobserver.on (.next("Cooci - frame class ")) anyobserver.on (.next("Cooci - frame class "))You have to focus on thisAnyObserverCall theonThe message inside is.next function..next functionWith 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)
    }
}

Copy the code
  • self.observerConstructor initialization is:AnonymousObservableSink. On function
  • See here to transform again:self.observer(event) -> AnonymousObservableSink .on(event)Among themEvent =.next("Cooci - Frame class ")Eventually our core logic comes backsinkThis amazing tube, it’s amazing to see this,RxSwiftThis design ability, who else
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()
            }
        }
    }
}

Copy the code
  • self.forwardOn(event)This is also the core code to execute becauseAnonymousObservableSinkinheritanceSinkThere is also encapsulation, as shown in 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)
    }
}

Copy the code
  • Among themself._observerThat’s what we initialized to saveObserver: AnonymousObserver
  • So we transform it to get the essence:Anonymousobserver.on (.next("Cooci - frame class "))Oh my god! Here logic comes back to usSubscribe to the sequenceCreated whenAnonymousObserverA call to the parameter closure of! Everything feels so wordy, but it’s so resourceful.
let observer = AnonymousObserver<E> { event in
    switch event {
    case .next(letvalue): onNext? (value)case .error(let error):
        if let onError = onError {
            onError(error)
        }
        else {
            Hooks.defaultErrorHandler(callStack, error)
        }
        disposable.dispose()
    case .completed:
        onCompleted?()
        disposable.dispose()
    }
}

Copy the code
  • judgeeventAnd then callonNext? (value)Because the associated values of enumerations (SwiftVery powerful function)Value = "Cooci - frame class"And then there’s the outside worldCall to the onNext closure, so this time source code parsing here, I believe you have fully masteredRxSwiftFinally, here is attached our analysis diagram

Summary: RxSwift structure

  • 1: Is the sequence of feelings all over the world sequence – unified coding, anytime, anywhere to enjoy
  • 2: Sink a list of requirements through functional thinking (encapsulating what developers don’t care about) – optimize code and save logic
  • 3:RxSwiftThe most typical feature is resolutionSwiftThe response capability of this static language, using the time dimension series changes as the axis, the user subscription care can be kept alive along with the axis, reach the subscription once, the response has been continued ~

For RxSwift, you have a better understanding. If you want to have a better discussion, you can enter the iOS technology group to discuss and communicate with them

  • Click to join the iOS developer group for discussion