Understanding RxSwift: Why use RxSwift (part 1)

Understanding RxSwift: Implementation Principles (part 2)

RxSwift: MVVM (3)

Understanding RxSwift: Unit Testing (Part 4)

How does RxSwift run internally, what is the relationship between Observable and Observer, and how is Operator implemented? If we want to thoroughly understand RxSwift, we can write a simple RxSwift to help us really understand its implementation principle. To better use RxSwift for development.

The basic principle of

RxSwift is an expanded version of observer mode, but ultimately observer mode. User input, click events, timers, network requests, etc., can all be regarded as observables. Observers always register a subscription with an Observable. When an event occurs, the Observable finds all subscriptions and notifies the Observer.

Observer model

A brief introduction to the observer mode, skip this section if you are already familiar with it.

When an object’s state changes, all objects that depend on it are notified and react. For example, in MVC, the Model is the Subject in the Observer mode, and the View is the Observer in the Observer mode. When the Model changes, a notification is triggered to update the View listening to it.

Let’s write a simple observer in Swift:

//Observer pattern
protocol Observer {
    func update(message: String)
}

class Subject {
    var observers: Array<Observer> = []
    
    func register(observer:Observer) {
        self.observers.append(observer)
    }
    
    func notify(message: String) {
        for observer in observers {
            observer.update(message: message)
        }
    }
}
class Observer1: Observer {
    func update(message: String) {
        print("Observer1: " + message)
    }
}

class Observer2: Observer {
    func update(message: String) {
        print("Observer2: " + message)
    }
}
Copy the code

The observed Subject class internally stores the objects to which it is subscribed, and these subscribed observers are notified when a Subject is updated.

let subject = Subject()
let observer1 = Observer1()
let observer2 = Observer2()

subject.register(observer: observer1)
subject.register(observer: observer2)

subject.notify(message: "zcj")
Copy the code

Observable

An Observable is essentially a function that accepts a subscription function that triggers updates when an event occurs.

//simple 1: Observable
typealias EventHandler = (String) -> Void

func myObservable(eventHandler: EventHandler) {
    eventHandler("zcj")
    eventHandler("hello")
    eventHandler("world")}let eventHandler : EventHandler = {(value) -> Void in
    print(value)
}
myObservable(eventHandler: eventHandler)
Copy the code

The closure EventHandler is defined above, passing in a String argument with no return value. Instantiate a closure object, eventHandler, that simply prints the incoming content.

The myObservable function receives a closure and calls it as needed.

Observer

Observable encapsulates Observable as a class, which makes it easy to pass in an Observer as an anonymous object and use it in a simple way

let observable = Observable{(observer) -> Void in
    observer.next(value: "zcj")}let closure = {(value: String) -> Void in
    print(value)
}
observable.subscribe(eventHandler: closure)
Copy the code

To achieve this effect, we first wrap the subscription function into the Observer class and add a next function that, when called, executes the subscription function held by the Observer.

// Simple 2: Observer Class Observer {typeAlias EventHandler = (String) -> Void privatelet _eventHandler : EventHandler
    init(eventHandler: @escaping EventHandler) {
        self._eventHandler = eventHandler
    }

    func next(value: String) {
        self._eventHandler(value)
    }
}

func myObservable(handle: @escaping (String) -> Void) {
    let observer = Observer(eventHandler: handle)
    observer.next(value: "zcj")}let closure = {(value: String) -> Void in
    print(value)
}
myObservable(handle: closure)
Copy the code

Observables also wrap classes that are created as observers by subscribeHandler

//simple 3
typealias EventHandler = (String) -> Void
typealias SubscribeHandler = (Observer) -> Void

class Observer {
    private let _eventHandler : EventHandler
    init(eventHandler: @escaping EventHandler) {
        self._eventHandler = eventHandler
    }

    func next(value: String) {
        self._eventHandler(value)
    }
}

class Observable {

    private let subscribeHandler: SubscribeHandler

    public init(_ subscribeHandler: @escaping SubscribeHandler) {
        self.subscribeHandler = subscribeHandler
    }

    public func subscribe(eventHandler: @escaping EventHandler) {
        let observer = Observer(eventHandler: eventHandler)
        self.subscribeHandler(observer)
    }
}

let observable = Observable{(observer) -> Void in
    observer.next(value: "zcj")}let closure = {(value: String) -> Void in
    print(value)
}
observable.subscribe(eventHandler: closure)
Copy the code

Operator

The operator in RxSwift is actually a receiving source Observable, which returns a new Observable after processing. We implemented a simple map operator with the following code:

//simple 4

typealias EventHandler = (String) -> Void
typealias SubscribeHandler = (Observer) -> Void

class Observer {

    private let _eventHandler : EventHandler
    init(eventHandler: @escaping EventHandler) {
        self._eventHandler = eventHandler
    }

    func next(value: String) {
        self._eventHandler(value)
    }
}

class Observable {

    private let subscribeHandler: SubscribeHandler

    public init(_ subscribeHandler: @escaping SubscribeHandler) {
        self.subscribeHandler = subscribeHandler
    }

    public func subscribe(eventHandler: @escaping EventHandler) {
        let observer = Observer(eventHandler: eventHandler)
        self.subscribeHandler(observer)
    }
}

func map(source: Observable, transform: @escaping (_ value: String) -> String) -> Observable {
    return Observable({ (observer) in
        let closure = {(value: String) -> Void in
            let transformedValue = transform(value)
            observer.next(value: transformedValue)
        }
        source.subscribe(eventHandler: closure)
    })
}

let observable = Observable{(observer) -> Void in
    observer.next(value: "zcj")}let closure = {(value: String) -> Void in
    print(value)
    print(value)
    print(value)
}

map(source: observable) { (value) -> String in
    return "hi " + value
}.subscribe(eventHandler: closure)
Copy the code

Inside the Map, a new Observable is generated based on the transform closure passed in from the outer layer.

Inside the new Observable, a closure is created to convert a value into a transformedValue. The original Sourec subscribs to this closure and notifys the internal Observer to update when the outer Observable is being monitored.

Demo: github.com/superzcj/Rx…

conclusion

Firstly, we introduce the basic principle of RxSwift theoretically, and then use Swift to realize the Observer mode, which is the basis of RxSwift. Finally, we implement Observable, Observer and Operator respectively.

All of the above belong to the core of RxSwift, we complete the implementation again, I believe that in this process, we will have a deeper understanding of RxSwift, but also better use of RxSwift development.

In the next article, we’ll look at how RxSwift can be combined with MVVM to better serve our business development.

The resources

RXJS principle analysis of their own build one