2018-04-27,app 启动时间优化,3

看下 RxSwift 的双向绑定, 及 RxCocoa 的相关源代码

一般 RxSwift 用于 MVVM, MVVM 常用功能就是双向绑定,Model 和 UI 的相互数据关联。

看下官方的 <->

在 RxSwift 的案例代码中,有一个 Operators.swift 文件,提供了一个 <-> 双向绑定操作符函数。

func <-> (property: ControlProperty, relay: BehaviorRelay) -> Disposable {
    let bindToUIDisposable = relay.bind(to: property)
    let bindToRelay = property
        .subscribe(onNext: { n in
            relay.accept(n)
        }, onCompleted:  {
            bindToUIDisposable.dispose()
        })

    return Disposables.create(bindToUIDisposable, bindToRelay)
}

代码逻辑很清晰,relay.bind(to: property), 模型绑定 UI, bindRxCocoasubscribe 的封装,换句话,UI 订阅了模型的事件。
property.subscribe, 模型订阅了 UI 的事件。

就这样,双向绑定完成了。

为什么不会陷入事件循环?

打个比方,如下代码,模型与 UI 绑定,点击按钮改模型,给模型传入一个事件。

(textFieldOne.rx.text <-> messageVal).disposed(by: disposeBag)
btn.rx.tap.subscribe(onNext: { (_) in
            self.messageVal.accept("Go")
        }).disposed(by: disposeBag)

模型 messageVal 收到一个事件,传给 UI textFieldOne.rx.text, textFieldOne.rx.text UI 传给模型 messageVal,模型 messageVal 再次传给 UI ...

实际上是没有死循环的。

可以简单理解为 textFieldOne.rx.text 做了保护。

下面是 UITextField+Rx.swift 的源代码。

extension Reactive where Base: UITextField {
    /// Reactive wrapper for `text` property.
    public var text: ControlProperty {
        return value
    }
    

    /// Reactive wrapper for `text` property.
    public var value: ControlProperty {
        return base.rx.controlPropertyWithDefaultEvents(
            getter: { textField in
                textField.text
            },
            setter: { textField, value in
                // This check is important because setting text value always clears control state
                // including marked text selection which is imporant for proper input 
                // when IME input method is used.
                if textField.text != value {
                    textField.text = value
                }   
            }
        )
    }

textFieldOne.rx.text 里面的 .text, 是一个计算属性,是 value 起作用。
value 又是一个计算属性,计算属性就是方法( getter/ setter 函数),

直观的看到一个 if if textField.text != value {, 这样不会老是要把 textField 拎出来写入。

起作用的是 base.rx.controlPropertyWithDefaultEvents,

UIControl+Rx.swift 的源代码:

internal func controlPropertyWithDefaultEvents(
        editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
        getter: @escaping (Base) -> T,
        setter: @escaping (Base, T) -> Void
        ) -> ControlProperty {
        return controlProperty(
            editingEvents: editingEvents,
            getter: getter,
            setter: setter
        )
    }

结论: 这里只用到了 [.allEditingEvents, .valueChanged] 两种事件 UIControl.Event .

然后对 UIControl 建立 target action 机制,因为只有编辑和修改的控件事件,所以直接对 textField.text 赋值,是订阅不到的。

这样改模型 messageVal,模型 messageVal 收到一个事件,传给 UI textFieldOne.rx.text, 就完了。

这样改UI textFieldOne.rx.text,UI textFieldOne.rx.text 收到一个事件,传给 模型 messageVal,模型 messageVal 收到 UI 一个事件,再次传给 UI textFieldOne.rx.text, 就完了。

再看下, RxCocoa 是怎样建立 Target Action 的

还是 UIControl+Rx.swift 文件

/// Creates a `ControlProperty` that is triggered by target/action pattern value updates.
    ///
    /// - parameter controlEvents: Events that trigger value update sequence elements.
    /// - parameter getter: Property value getter.
    /// - parameter setter: Property value setter.
    public func controlProperty(
        editingEvents: UIControl.Event,
        getter: @escaping (Base) -> T,
        setter: @escaping (Base, T) -> Void
    ) -> ControlProperty {
// 处理 getter
        let source: Observable = Observable.create { [weak weakControl = base] observer in
                guard let control = weakControl else {
                    observer.on(.completed)
                    return Disposables.create()
                }
     // 上面是内存管理,避免循环引用的 weak strong dance, 下面开始做正事
                observer.on(.next(getter(control)))
// 建立 target - action
                let controlTarget = ControlTarget(control: control, controlEvents: editingEvents) { _ in
                    if let control = weakControl {
                        observer.on(.next(getter(control)))
                    }
                }
                
                return Disposables.create(with: controlTarget.dispose)
            }
            .takeUntil(deallocated)
// 处理 setter
        let bindingObserver = Binder(base, binding: setter)

        return ControlProperty(values: source, valueSink: bindingObserver)
    }

在 ControlTarget.swift 文件中,添加 target action 相对简单清晰

final class ControlTarget: RxTarget {
    typealias Callback = (Control) -> Void

    let selector: Selector = #selector(ControlTarget.eventHandler(_:))

    weak var control: Control?

    let controlEvents: UIControl.Event

    var callback: Callback?

    init(control: Control, controlEvents: UIControl.Event, callback: @escaping Callback) {
// 确保主线程
        MainScheduler.ensureRunningOnMainThread()
// init 属性
        self.control = control
        self.controlEvents = controlEvents
        self.callback = callback

        super.init()
    //  添加 target action
        control.addTarget(self, action: selector, for: controlEvents)

        let method = self.method(for: selector)
        if method == nil {
            rxFatalError("Can't find method")
        }
    }


...





看下 RxBiBinding 源代码,

上正菜,RxBiBinding 源代码

RxBiBinding 作为专业做双向绑定的,提供了三种场景,模型( 行为主体 )绑定模型,控件绑定控件,模型绑定控件。

// 控件绑定控件
public func <->(left: ControlProperty, right: ControlProperty) -> Disposable {}
//  模型绑定模型
public func <->(left: BehaviorRelay, right: BehaviorRelay) -> Disposable {}
// 模型绑定控件
public func <->(left: ControlProperty, right: BehaviorRelay) -> Disposable {}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

涉及的框架与服务,真是多啊。

WXApiService
// 微信服务

UMSocialService
// 友盟相关

TingyunAppService
// 听云sdk接入

你可能感兴趣的:(2018-04-27,app 启动时间优化,3)