RxSwift之traits后篇:RxCocoa traits

這里是原文:Traits (formerly Units)
這一篇是整篇翻譯的后半部分捺檬,建議先看看前半部分:RxSwift之traits前篇:RxSwift traits

RxCocoa traits


Driver

這是最復(fù)雜的trait,它的目標(biāo)是提供一種簡(jiǎn)便的方式在UI層編寫(xiě)響應(yīng)式代碼秋泄,或者任何你想模擬驅(qū)動(dòng)你的App的數(shù)據(jù)流的情況。

  • 不能拋出錯(cuò)誤
  • 監(jiān)聽(tīng)發(fā)生在主線(xiàn)程
  • 分享副作用(shareReplayLatestWhileConnected)
為什么命名為Driver

它的目標(biāo)用例是作為驅(qū)動(dòng)你的App的序列模型谱净。
例如:

  • 由CoreData模型驅(qū)動(dòng)UI
  • 使用其他UI元素(綁定)的值驅(qū)動(dòng)UI

就像正常的操作系統(tǒng)驅(qū)動(dòng)程序一樣放闺,假如一個(gè)序列拋出錯(cuò)誤凶赁,你的應(yīng)用程序就會(huì)停止響應(yīng)用戶(hù)操作观蜗。
那些元素在主線(xiàn)程被監(jiān)聽(tīng)臊恋,這極其重要,因?yàn)閁I元素和程序邏輯通常不是線(xiàn)程安全的墓捻。
此外抖仅,Driver建立了一個(gè)分享副作用的可觀(guān)察序列。
例如:

實(shí)際使用的例子

這是一個(gè)典型的初學(xué)者例子:

let results = query.rx.text
    .throttle(0.3, scheduler: MainScheduler.instance)
    .flatMapLatest { query in
        fetchAutoCompleteItems(query)
    }

results
    .map { "\($0.count)" }
    .bind(to: resultCount.rx.text)
    .disposed(by: disposeBag)

results
    .bind(to: resultsTableView.rx.items(cellIdentifier: "Cell")) { (_, result, cell) in
        cell.textLabel?.text = "\(result)"
    }
    .disposed(by: disposeBag)```
以上代碼的預(yù)期行為是:
* 節(jié)流用戶(hù)輸入
* 聯(lián)系服務(wù)器并獲取用戶(hù)結(jié)果列表(每次查詢(xún)一次)
* 綁定結(jié)果到兩個(gè)UI元素:results table view和一個(gè)顯示結(jié)果數(shù)字的label

那么砖第,這個(gè)代碼有什么問(wèn)題呢撤卢?
* 如果`fetchAutoCompleteItems `可觀(guān)察序列拋出錯(cuò)誤(連接失敗或者是解析錯(cuò)誤),這個(gè)錯(cuò)誤將會(huì)解綁所有元素梧兼,并且UI不會(huì)再響應(yīng)新的查詢(xún)放吩。
* 如果`fetchAutoCompleteItems`在某個(gè)后臺(tái)線(xiàn)程返回結(jié)果,這些結(jié)果將會(huì)從一個(gè)后臺(tái)線(xiàn)程綁定到UI元素上羽杰,這將會(huì)導(dǎo)致不確定的崩潰屎慢。
* 結(jié)果被綁定到兩個(gè)UI元素上瞭稼,這就意味著忽洛,對(duì)于每個(gè)用戶(hù)查詢(xún)腻惠,都會(huì)建立兩個(gè)HTTP請(qǐng)求,每個(gè)UI元素對(duì)應(yīng)一個(gè)欲虚,這并不是預(yù)期的行為集灌。

一個(gè)更為合適的代碼版本如下:

let results = query.rx.text
.throttle(0.3, scheduler: MainScheduler.instance)
.flatMapLatest { query in
fetchAutoCompleteItems(query)
.observeOn(MainScheduler.instance) // results are returned on MainScheduler
.catchErrorJustReturn([]) // in the worst case, errors are handled
}
.shareReplay(1) // HTTP requests are shared and results replayed
// to all UI elements

results
.map { "($0.count)" }
.bind(to: resultCount.rx.text)
.disposed(by: disposeBag)

results
.bind(to: resultsTableView.rx.items(cellIdentifier: "Cell")) { (_, result, cell) in
cell.textLabel?.text = "(result)"
}
.disposed(by: disposeBag)```
確保所有這些要求在大型系統(tǒng)中被正確處理很有挑戰(zhàn)性,但有一種簡(jiǎn)單的使用編譯器和traits來(lái)證明這些要求得到滿(mǎn)足的方法复哆。
下面的代碼看起來(lái)幾乎一樣:

let results = query.rx.text.asDriver()        // This converts a normal sequence into a `Driver` sequence.
    .throttle(0.3, scheduler: MainScheduler.instance)
    .flatMapLatest { query in
        fetchAutoCompleteItems(query)
            .asDriver(onErrorJustReturn: [])  // Builder just needs info about what to return in case of error.
    }

results
    .map { "\($0.count)" }
    .drive(resultCount.rx.text)               // If there is a `drive` method available instead of `bindTo`,
    .disposed(by: disposeBag)              // that means that the compiler has proven that all properties
                                              // are satisfied.
results
    .drive(resultsTableView.rx.items(cellIdentifier: "Cell")) { (_, result, cell) in
        cell.textLabel?.text = "\(result)"
    }
    .disposed(by: disposeBag)```
那么這里發(fā)生了什么欣喧?
第一個(gè)`asDriver`方法把trait`ControlProperty `轉(zhuǎn)換成trait`Driver `。

query.rx.text.asDriver()```
注意沒(méi)有任何特別的事情需要做梯找。Driver擁有ControlProperty所有的屬性唆阿,加上一些其他的。底層的可觀(guān)察序列只是被封裝成了一個(gè)Drivertrait锈锤,就是這樣驯鳖。

第二個(gè)變化是:

.asDriver(onErrorJustReturn: [])```
任何可觀(guān)察序列都能被轉(zhuǎn)化為`Driver`,只要它滿(mǎn)足三個(gè)屬性:
* 不能拋出錯(cuò)誤
* 在主線(xiàn)程監(jiān)聽(tīng)
* 分享副作用(`shareReplayLatestWhileConnected `)

那么如何確保這些屬性得到滿(mǎn)足呢久免?只使用標(biāo)準(zhǔn)的Rx操作符浅辙。
`asDriver(onErrorJustReturn: []) `和以下代碼是等價(jià)的。

let safeSequence = xs
.observeOn(MainScheduler.instance) // observe events on main scheduler
.catchErrorJustReturn(onErrorJustReturn) // can't error out
.shareReplayLatestWhileConnected // side effects sharing
return Driver(raw: safeSequence) // wrap it up```
最后一件事是用drive代替bindTo阎姥。
drive只在Driver特性里定義记舆。這就意味著,如果你在某些代碼里看到drive呼巴,那個(gè)可觀(guān)察序列絕不會(huì)拋出錯(cuò)誤泽腮,并且它在主線(xiàn)程監(jiān)聽(tīng),這對(duì)于綁定一個(gè)UI元素來(lái)說(shuō)是安全的衣赶。

注意诊赊,然而理論上,別人仍然可以為ObservableType或者是一些其他接口定義一個(gè)drive方法來(lái)工作屑埋,因此為了更加安全鸥咖,在綁定UI元素之前用let results: Driver<[Results]> = ...創(chuàng)建一個(gè)臨時(shí)的定義是有必要的。然而些楣,我們將留給讀者來(lái)決定這是否是一個(gè)現(xiàn)實(shí)的方案另伍。

ControlProperty / ControlEvent

  • 不能拋出錯(cuò)誤
  • 訂閱發(fā)生在主線(xiàn)程
  • 監(jiān)聽(tīng)發(fā)生在主線(xiàn)程
  • 分享副作用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市团搞,隨后出現(xiàn)的幾起案子严望,更是在濱河造成了極大的恐慌,老刑警劉巖逻恐,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件像吻,死亡現(xiàn)場(chǎng)離奇詭異峻黍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拨匆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)姆涩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惭每,你說(shuō)我怎么就攤上這事骨饿。” “怎么了台腥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵宏赘,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我黎侈,道長(zhǎng)察署,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任峻汉,我火速辦了婚禮贴汪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俱济。我一直安慰自己嘶是,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布蛛碌。 她就那樣靜靜地躺著聂喇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔚携。 梳的紋絲不亂的頭發(fā)上希太,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音酝蜒,去河邊找鬼誊辉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛亡脑,可吹牛的內(nèi)容都是我干的堕澄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼霉咨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蛙紫!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起途戒,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坑傅,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后喷斋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體唁毒,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒜茴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浆西。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粉私。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖室谚,靈堂內(nèi)的尸體忽然破棺而出毡鉴,到底是詐尸還是另有隱情,我是刑警寧澤秒赤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站憎瘸,受9級(jí)特大地震影響入篮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幌甘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一潮售、第九天 我趴在偏房一處隱蔽的房頂上張望锅风。 院中可真熱鬧,春花似錦肮帐、人聲如沸边器。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)耸采。三九已至洋幻,卻和暖如春翅娶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背骑篙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杨名,地道東北人台谍。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像掷伙,于是被迫代替她去往敵國(guó)和親任柜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乘盼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理页屠,服務(wù)發(fā)現(xiàn),斷路器风纠,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 亞歷山大 · 亞歷山德羅維奇 · 柳比歇夫(1890 年 4 月 5 日——1972 年 8 月 31 日),前蘇...
    二石兄閱讀 365評(píng)論 0 0
  • 鄭姐談起她女兒的時(shí)候,眼眶紅了瞎领。 她說(shuō)因?yàn)楣ぷ髟蛩婵洌阉莾蓺q多的寶貝女兒留在老家逃魄,讓孩子的爺爺奶奶帶伍俘。鄭姐只是偶...
    云朵朵啊閱讀 61,812評(píng)論 5 9
  • 朱妍這幾天愁的緊。 杭州的雨一直下饵溅,洗的衣服一直潮著蜕企。 她做夢(mèng)都想來(lái)個(gè)大晴天轻掩,一股腦兒的都給殺殺菌。被單也該洗了罕扎。...
    唐小茴閱讀 262評(píng)論 2 0