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
rx
isprotocol ReactiveCompatible
The properties of thestatic var rx
Is a class variable,var rx
Is an instance variable of typeReactive<ReactiveBase>
.associatedtype
The key word is forprotocol
Provides generic functionality.Reactive
Follow theReactiveCompatible
Agreement, thenReactive
The generic type of theReactiveBase
.- In Swift, we can go through
extension protocol
To 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
-
Define a protocol ReactiveCompatible that has an attribute rx of type Reactive.
-
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
-
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
- extension
Reactive
To addtap
Properties,where Base: UIButton
Indicates that this property only givesUIButton
Add.
// 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