thought

“When a thousand cooks cook shredded pork with fish flavor, they will produce a thousand tastes.” — Du Fu’s process of cooking shredded pork with fish flavor is fixed, but there will be different results with different conditions, and even error. The procedure, written in RxSwift, would look like this:

        letCreate {(cook) -> The person who cleans up the kitcheninChopping vegetables (); Cook. Cook. For the next person ("Sliced vegetables."); Cook. Do. Finish (). Cook. Do. Fail ("No knife!);
            returnThe person who cleans the kitchen. Create (); }letCook = process <Any>. Create {(cook) -> the person who cleans up the kitcheninCooking (); Cook. Cook. For the next person ("Cooked dishes."); Cook. Do. Finish (). Cook. Do. Fail ("No pot!);
            returnThe person who cleans the kitchen. Create (); }letFlatMap {(Any) -> Process <Any>in 
               returnStir fry; }; Shredded pork with fish flavor. Made (for next person: {(semi-finished product)inTo serve (unserved dishes); }, complete: {printThis dish is finished. }, fail: {(error)in 
             printThis dish is not finished because :\(error)); // This dish is not finished because: there is no knife or pot});Copy the code

Here we can see that one of the basic ideas of RxSwift is to create a task, which is created with the result of the task, whether it is completed, and the aftermath considered. Then, when it’s time to do the task, start the task directly. When the task is started, an anonymous executor is automatically assigned to perform the task. There are three main members: the dishes, the cooks, and the people who clean the kitchen.

Then look at a simple RxSwift call code 1.1:

        let requestTask = Observable<Any>.create { (obserber) -> Disposable in
            obserber.on(.next("Return data 1"));
            obserber.onNext("Return data 2");
            return Disposables.create();
        }
        
        
        let _ = requestTask.subscribe(onNext: { (text) in
            print("Result :\(text)");
        });
Copy the code

structure

There are three cores to this


Figure 1


* Note: This is an unofficial picture drawn by the author in green: Extension in Swift language. Red: enumeration type Blue: structure

From figure 1 we can see RxSwift inside there are three main core protocol, namely < ObservableConvertibleType > subclasses of < ObservableType >, < ObserverType > and < the Disposable >. In layman’s terms, these are “agreements for what needs to be done,” “agreements for who does it,” and “agreements for who cleans it up.”

Are you intimidated by so many categories? In fact, a little division is very clear:


Figure 2


There are five major sections, each with a main class (highlighted in red). Let’s analyze them one by one

Note: Make sure to check whether it is an Observable or observer

Analysis of the

0 – asXXXX

There are a number of asXXX methods throughout Rx, but as subclassing continues, classes that implement this protocol may have other identities as well as one. The method protocol is there for readability and logic. For example, Xiao Ming used to be a programmer but he turned into a cook, so xiao Ming is now a cook, and cooks type code, which is very confusing but:

Xiao Ming. As a programmer. Knock code ()Copy the code

That makes sense.

1 – Event

The enumeration is a core, as you can see by the number of arrows pointing to it. This enumeration represents three cases of an event: Next, complete, and error. Both next and error are bound to associated values.

2.1 –

The basic agreement of the “working man”.

  1. Func on(_ event: event

    ) is the most basic protocol that a responder (a worker) needs to follow. This contains only this method and the parameter is the event mentioned above.

  2. Public func onNext(_ Element: E), public func onCompleted(), public func onError(_ error: Swift.error) for the 2.1.1 extension, we can see from the source that only the corresponding enumeration values are being sent. And on onNext and onError, assign parameters to the associated values of the enumeration.

2.2 – public struct AnyObserver

As the only structure in this article, the structure is used because it does not need to be inherited and does not need to be destructed. There is only one attribute :(Event<Element>) -> observer of type Void.

  1. Public init

    (_ observer: O) where O.E == Element
self.observer = observer.on
Copy the code

This is tricky because both the method prototype of the ON method and the closure type of the Observer are

 (Event<Element>) -> Void
Copy the code

So it can be assigned.

  1. Public func on(_ event: event

    ) Public func on(_ event: event

    ) Implements the protocol’s on method, which calls its own closure object observer with event as an argument.

3 – final class AnonymousObserver

This is basically a 2.2 enhancement that has destructor handling because it is not a structure but a class, and itself inherits from the Class ObserverBase<ElementType> class. The basic logic here is basically similar to 2.2, but the only difference is that it includes the implementation of the <Disposable> agreement. We will focus on <Disposable> in the following articles, so we won’t go into too much detail here.

4.1 – < ObservableType >

A basic agreement on what needs to be done.

  1. func subscribe

    (_ observer: O) -> Disposable where O.E == E — The basic protocol of all Observables, including the basic function subscribe. An Observable can at least subscribe to a cook (Observer) and return a Disposable to clean up the mess when appropriate.

  2. public static func create(_ subscribe: @escaping (AnyObserver

    ) -> Disposable -> Observable

    – This protocol extends a simple factory method to quickly create an instance of the AnonymousObservable class through a closure. (AnonymousObservable will be covered later)

  3. public func subscribe(_ on: @escaping (Event

    ) -> Void) -> Disposable — For method 1 extension, with an escape closure of (Event

    ) -> Void as an argument, Create an instance of AnonymousObserver class that implements ObserverType and call method 1.

  4. public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable — looks very complicated, but the real core code is only created in the middle of the AnonymousObserver, which takes onNext, onError, The closure of onCompleted passes in the associated value and calls back in the case of the corresponding enumerated value. The onDisposed closure is used to create a disposable, call disposable.dispose() when appropriate. When you finally create Disposables, call your subscribe method with the previous AnonymousObserver object as an argument.

4.2 class Producer

  1. func run

    (_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element — newly added abstract method. Returns two Disposable objects with an object of ObserverType subclass and an object of Cancelable (Disposable subclass) as arguments.

  2. Override func subscribe

    (_ observer: O) -> Disposable where O.E == Element

let disposer = SinkDisposer()
let sinkAndSubscription = self.run(observer, cancel: disposer)
Copy the code

This method generates a Disposer of its own, and then calls its run method with this Disposer and Observer as parameters.

4.3 – final private class AnonymousObservable

  1. _subscribeHandler and init

This final class adds a property

let _subscribeHandler: (AnyObserver<Element>) -> Disposable
Copy the code

The constructor assigns this property

init(_ subscribeHandler: @escaping SubscribeHandler) {
        self._subscribeHandler = subscribeHandler
}
Copy the code

Combined with 4.1.2, we can see that the _subscribeHandler is the block that is passed when we call creat. That’s code 1.1

obserber.on(.next("Return data 1"));
obserber.onNext("Return data 2");
return Disposables.create();
Copy the code
  1. 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)
Copy the code

1) AnonymousObservable’s run method is actually the run method of AnonymousObservableSink. 2) The first line shows that an instance of the AnonymousObservableSink class may contain an Observer as well as dispose. The second line shows that an instance of the AnonymousObservableSink class may also contain observeable. In other words, the AnonymousObservableSink class is the meeting point of the

mentioned above,< ObservableType >, and < Disposable > mentioned later. He is the nexus that brings together and harmonizes the work to be done, the worker, and the handler

5. – final private class AnonymousObservableSink

When you look at the two methods of this class, run and on, does it feel like everything is coming together here? Since Run is an Observable method and on is an Observer method, a single class contains both methods, demonstrating the class’s status as a hub.

  1. Func on(_ event: event

    ) func on(_ event: event

    ) func on(_ event: event

    ) func on(_ event: event

    ) func on(_ event: event

    ) func on(_ event: event

    )





  2. Func run(_ parent: parent) -> Disposable

let anyObserver = AnyObserver(self);
parent._subscribeHandler(observer);
Copy the code

Note that anyObserver is distinguished from an observer of its own nature. Its observer is an object of class (3) AnonymousObserver. AnyObserver is the object of structure anyObserver (2.2). (The difference was mentioned earlier in the AnonymousObserver class). These two lines of code generate an AnyObserver object and call the _subscribeHandler closure above with it as a parameter. Again, take code 1.1.

        let requestTask = Observable<Any>.create { (obserber) -> Disposable in
            obserber.on(.next("Return data 1"));
            obserber.onNext("Return data 2");
            return Disposables.create();
        }
Copy the code

Obserber here is AnyObserver(self).

conclusion

The core of RxSwift is very convoluted and fascinating, just remember Obserable -subscribe (Observer) -run (Observer); ⬆ ️ on (Event) – Sink — — — — — — — the run (AnyObserver) ⬆ ️ Observer – on (Event); And it’s relatively easy to think through the combination of source code and UML diagrams.


As a developer, it’s especially important to have a learning atmosphere and a communication circle, which is mine
Communication groupIf you are interested, you can join the group to communicate and learn together

Citation: Original address



Give me a thumbs up if you think it’s good. Thank you