The starting address: www.ljcoder.com/16073927284…

RxSwift profile

RxSwift is a functional responsive framework, using FRP(functional responsive programming) programming ideas. It is programming by building functions that manipulate sequences of data and then respond to those sequences. For basic use, please refer to the official RxSwift Chinese documentation.

What is rx?

In the use of RxSwift we often see the following code:

cameraButton.rx.tap
    .bind(to: imageView.rx.image)
    .disposed(by: disposeBag)
Copy the code

So what is rx? Let’s click in and find the following source code

/// A type that has reactive extensions.
public protocol ReactiveCompatible: AnyObject {
    /// associatedType is used to implement the generic function of protocol
    associatedtype ReactiveBase: AnyObject

    /// Reactive class variables
    static var rx: Reactive<ReactiveBase>.Type { get set }

    /// Reactive instance variables
    var rx: Reactive<ReactiveBase> { get set}}// Provide default get and SET implementations for two Rx variables via extension Protocol
extension ReactiveCompatible {
    /// Class variables set and get are implemented by default
    public static var rx: Reactive<Self>.Type {
        get { Reactive<Self>.self }
        
        set{}}/// Set and get are implemented by default for instance variables
    public var rx: Reactive<Self> {
        get { Reactive(self)}set{}}}Copy the code
  1. rxisprotocol ReactiveCompatibleThe properties of thestatic var rxIs a class variable,var rxIs an instance variable of typeReactive<ReactiveBase>.
  2. associatedtypeThe key word is forprotocolProvides generic functionality.ReactiveFollow theReactiveCompatibleAgreement, thenReactiveThe generic type of theReactiveBase.
  3. In Swift, we can go throughextension protocolTo provide a default implementation for properties or methods of the protocol.
public struct Reactive<Base: AnyObject> {
    // base stores generic variables
    public let base: Base

    /// construct method
    public init(_ base: Base) {
        self.base = base
    }
}
Copy the code

The Reactive structure has a Base property that stores the current instance object for invoking base instance methods.

The core logic

  1. Define a protocol ReactiveCompatible that has an attribute rx of type Reactive.

  2. NSObject follows the protocol ReactiveCompatible so that all classes have the property Rx.

    // NSObject follows the ReactiveCompatible protocol, which guarantees that all classes have RX properties
    extension NSObject: ReactiveCompatible {}Copy the code
  3. We typically use RxSwift in the following way. When button.rx is executed, we can see that the type returned is Reactive

    , so we need to add the tap property to extend the Reactive class.

// RxSwift
let button = UIButton()
button.rx.tap
        .subscribe(onNext: {
            print("UIButton Tapped")
        })
        .disposed(by: disposeBag)
Copy the code

  1. extensionReactiveTo addtapProperties,where Base: UIButtonIndicates that this property only givesUIButtonAdd.
// If you want to add properties or methods to UIButton, you need to extend the Reactive structure. The WHERE syntax specifies that the extended properties or methods belong only to UIButton
extension Reactive where Base: UIButton {
    
        public var tap: ControlEvent<Void> {
            controlEvent(.touchUpInside)
        }
}
Copy the code

Added: Reactive base properties

In the URLSession extension method, we can see the use of the Base attribute, which is mainly used when calling URLSession’s own methods.

extension Reactive where Base: URLSession {
    public func response(request: URLRequest) -> Observable<(response: HTTPURLResponse, data: Data) > {return Observable.create { observer in
            let d: Date?

            if URLSession.rx.shouldLogRequest(request) {
                d = Date()}else {
               d = nil
            }
            
            // Base is the URLSession instance
            let task = self.base.dataTask(with: request) { data, response, error in

                if URLSession.rx.shouldLogRequest(request) {
                    let interval = Date().timeIntervalSince(d ?? Date())
                    print(convertURLRequestToCurlCommand(request))
                    #if os(Linux)
                        print(convertResponseToString(response, error.flatMap { $0 as NSError }, interval))
                    #else
                        print(convertResponseToString(response, error.map { $0 as NSError }, interval))
                    #endif
                }
                
                guard let response = response, let data = data else {
                    observer.on(.error(error ?? RxCocoaURLError.unknown))
                    return
                }

                guard let httpResponse = response as? HTTPURLResponse else {
                    observer.on(.error(RxCocoaURLError.nonHTTPResponse(response: response)))
                    return
                }

                observer.on(.next((httpResponse, data)))
                observer.on(.completed)
            }

            task.resume()

            return Disposables.create(with: task.cancel)
        }
    }
}
Copy the code