2018-04-27,app 啟動(dòng)時(shí)間優(yōu)化焙贷,3

看下 RxSwift 的雙向綁定撵割, 及 RxCocoa 的相關(guān)源代碼

一般 RxSwift 用于 MVVM, MVVM 常用功能就是雙向綁定,Model 和 UI 的相互數(shù)據(jù)關(guān)聯(lián)辙芍。

看下官方的 <->

在 RxSwift 的案例代碼中啡彬,有一個(gè) Operators.swift 文件,提供了一個(gè) <-> 雙向綁定操作符函數(shù)故硅。

func <-> <T>(property: ControlProperty<T>, relay: BehaviorRelay<T>) -> 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, bindRxCocoa 對(duì) subscribe 的封裝,換句話吃衅,UI 訂閱了模型的事件往踢。
property.subscribe, 模型訂閱了 UI 的事件。

就這樣徘层,雙向綁定完成了峻呕。

為什么不會(huì)陷入事件循環(huán)?

打個(gè)比方趣效,如下代碼山上,模型與 UI 綁定,點(diǎn)擊按鈕改模型英支,給模型傳入一個(gè)事件佩憾。

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

模型 messageVal 收到一個(gè)事件,傳給 UI textFieldOne.rx.text, textFieldOne.rx.text UI 傳給模型 messageVal,模型 messageVal 再次傳給 UI ...

實(shí)際上是沒有死循環(huán)的妄帘。

可以簡(jiǎn)單理解為 textFieldOne.rx.text 做了保護(hù)楞黄。

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

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

    /// Reactive wrapper for `text` property.
    public var value: ControlProperty<String?> {
        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, 是一個(gè)計(jì)算屬性抡驼,是 value 起作用鬼廓。
value 又是一個(gè)計(jì)算屬性,計(jì)算屬性就是方法( getter/ setter 函數(shù))致盟,

直觀的看到一個(gè) if if textField.text != value {, 這樣不會(huì)老是要把 textField 拎出來寫入碎税。

起作用的是 base.rx.controlPropertyWithDefaultEvents,

UIControl+Rx.swift 的源代碼:

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

結(jié)論: 這里只用到了 [.allEditingEvents, .valueChanged] 兩種事件 UIControl.Event .

然后對(duì) UIControl 建立 target action 機(jī)制,因?yàn)橹挥芯庉嫼托薷牡目丶录笪灾苯訉?duì) textField.text 賦值雷蹂,是訂閱不到的。

這樣改模型 messageVal杯道,模型 messageVal 收到一個(gè)事件匪煌,傳給 UI textFieldOne.rx.text, 就完了。

這樣改UI textFieldOne.rx.text党巾,UI textFieldOne.rx.text 收到一個(gè)事件萎庭,傳給 模型 messageVal,模型 messageVal 收到 UI 一個(gè)事件,再次傳給 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<T>(
        editingEvents: UIControl.Event,
        getter: @escaping (Base) -> T,
        setter: @escaping (Base, T) -> Void
    ) -> ControlProperty<T> {
// 處理 getter
        let source: Observable<T> = Observable.create { [weak weakControl = base] observer in
                guard let control = weakControl else {
                    observer.on(.completed)
                    return Disposables.create()
                }
     // 上面是內(nèi)存管理,避免循環(huán)引用的 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<T>(values: source, valueSink: bindingObserver)
    }

在 ControlTarget.swift 文件中署海,添加 target action 相對(duì)簡(jiǎn)單清晰

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 作為專業(yè)做雙向綁定的叹侄,提供了三種場(chǎng)景巩搏,模型( 行為主體 )綁定模型,控件綁定控件趾代,模型綁定控件贯底。

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


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

涉及的框架與服務(wù),真是多啊撒强。

WXApiService
// 微信服務(wù)

UMSocialService
// 友盟相關(guān)

TingyunAppService
// 聽云sdk接入

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末禽捆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子飘哨,更是在濱河造成了極大的恐慌胚想,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芽隆,死亡現(xiàn)場(chǎng)離奇詭異浊服,居然都是意外死亡统屈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門牙躺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愁憔,“玉大人,你說我怎么就攤上這事孽拷《终疲” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵脓恕,是天一觀的道長(zhǎng)膜宋。 經(jīng)常有香客問我,道長(zhǎng)炼幔,這世上最難降的妖魔是什么秋茫? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮江掩,結(jié)果婚禮上学辱,老公的妹妹穿的比我還像新娘乘瓤。我一直安慰自己环形,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布衙傀。 她就那樣靜靜地躺著抬吟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪统抬。 梳的紋絲不亂的頭發(fā)上火本,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音聪建,去河邊找鬼钙畔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛金麸,可吹牛的內(nèi)容都是我干的擎析。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼挥下,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼揍魂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棚瘟,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤现斋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后偎蘸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庄蹋,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞬内,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔓肯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遂鹊。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蔗包,靈堂內(nèi)的尸體忽然破棺而出秉扑,到底是詐尸還是另有隱情,我是刑警寧澤调限,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布舟陆,位于F島的核電站,受9級(jí)特大地震影響耻矮,放射性物質(zhì)發(fā)生泄漏秦躯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一裆装、第九天 我趴在偏房一處隱蔽的房頂上張望踱承。 院中可真熱鬧,春花似錦哨免、人聲如沸茎活。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽载荔。三九已至,卻和暖如春采桃,著一層夾襖步出監(jiān)牢的瞬間懒熙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工普办, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留工扎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓衔蹲,卻偏偏與公主長(zhǎng)得像肢娘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子踪危,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,163評(píng)論 25 707
  • 用到的組件 1蔬浙、通過CocoaPods安裝 2、第三方類庫(kù)安裝 3贞远、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 14,618評(píng)論 1 180
  • 一 國(guó)慶回家蓝仲,與高中同學(xué)L見面俱病,坐著聊天的時(shí)候官疲,無意間看到她手上的戒指,我笑說:“有情況傲料丁途凫!”她嘻嘻笑,“我訂婚了...
    木槿楠閱讀 392評(píng)論 1 3
  • 前言 最近在學(xué)習(xí)Rxjava2溢吻,雖然在實(shí)際的項(xiàng)目中使用也看了很多的文章和文檔维费,學(xué)會(huì)的了如何使用但是忘記的很快,也沒...
    g小志閱讀 814評(píng)論 0 5
  • 從小到大到大,好像我們沒有特別去關(guān)注睡眠蝇狼,睡覺誰不會(huì)啊阅畴,這還需要了解什么! 可事實(shí)是迅耘,我們還真不會(huì)科學(xué)睡眠贱枣,那么如...
    順鍋閱讀 224評(píng)論 0 1