iOS-ReactiveCocoa學習筆記1

一篇關(guān)于RectiveCocoa的總結(jié)文檔

百度搜索了一下RectiveCocoa,都是與MVVM關(guān)聯(lián)在一起。

1·簡述下MVVM

MVC:ModelViewViewController

MVVM:ModelViewView-Model

Model:容納表現(xiàn)數(shù)據(jù)-模型對象信息的結(jié)構(gòu)體,并在一個單獨的管理類中維護的創(chuàng)建/管理模型的統(tǒng)一邏輯。

View:包含實際 UI 本身(不論是 UIView 代碼, storyboard 和 xib), 任何視圖特定的邏輯, 和對用戶輸入的反饋. 在 iOS 中這不僅需要 UIView 代碼和那些文件, 還包括很多需由 UIViewController 處理的工作。

View-Model:

1、作為一個表現(xiàn)視圖顯示自身所需數(shù)據(jù)的靜態(tài)模型;

2、收集, 解釋和轉(zhuǎn)換那些數(shù)據(jù);

收集:網(wǎng)絡請求,control控制的數(shù)值變更;

解釋:賦值;

轉(zhuǎn)換:viewmodel內(nèi)的邏輯運算;

3、目的:讓view(controller)的任務更清晰,就是展示view-Model提供的數(shù)據(jù)。

Summary:Model不變,view不變,增加View-Model分擔ViewController的責任(每個view將有自己的view-model來約束)

其最終結(jié)果就是MVMCV

關(guān)于View-Model

不對視圖控制器起作用,或通告其變化

關(guān)于ViewController

1、不再發(fā)起網(wǎng)絡服務調(diào)用

2、不再管理數(shù)組(類似tableview的dataSource)

3、不再判斷某些值是否有效

4、其實就是不再管text或者image是什么了

5、只管view-Model中的變化

Summary:將view-model與view關(guān)聯(lián),通過修改view model中的值的變更來修改view中的數(shù)值變化;ViewController就只能老老實實的管view-model的數(shù)值變更就好了。

2·ReactiveCocoa

解決View和View-Model關(guān)聯(lián)的問題

舉例

假設(shè)這是一個登陸頁面,我要判斷用戶名是否合法,密碼是否匹配,這些在MVC的情況下我都會在Controller中進行判斷,是的話會怎么怎么樣,不是的話會怎么怎么樣。

而在MVVM和RectiveCocoa的幫助下,我們可以使用一個登陸的ViewModel,所有的判斷和結(jié)果我可以寫在ViewModel中。而在Controller中我只要1、關(guān)聯(lián)用戶名的text和viewmodel中的username,密碼對應。2、就不用管TA了。

RectiveCocoa的學習

概念,一直是我不想去背卻又不得不背的東西。

1、RACSignal:RAC的構(gòu)造單元,代表我們最終收到的信息,(當你能將未來某事某刻接收到的消息具體表示出來,我們可以預先運用邏輯構(gòu)建信息流,而不是等到事件發(fā)生)

簡述:

1、信號是基本單位,也是寫完代碼會接收到的東西,因為是數(shù)據(jù)關(guān)聯(lián)在view和view-model上,我們可以提前將需要展示出來的數(shù)據(jù)在viewmodel中處理了,再通過關(guān)聯(lián)影響view的值的變化。而不是在controller中書寫了。(個人理解,如有偏差,請各種指正)

2、信號會為了控制通過應用的信息流而獲得所有這些異步方法(委托, 回調(diào) block, 通知, KVO, target/action 事件觀察, 等)并將它們統(tǒng)一到一個接口下.這只是直觀理解. 不僅是這些, 因為信息會流過你的應用, 它還提供給你輕松轉(zhuǎn)換/分解/合并/過濾信息的能力.

簡述:中央集權(quán)制,信號中處理這些傳值方式;并通過書寫的邏輯達到預期的效果。

信號如何將ViewModel與View關(guān)聯(lián)上

信號是一個發(fā)送一連串值的物體。需要在訂閱者監(jiān)聽時信號才會發(fā)信息,信號會向訂閱者發(fā)送0或多個帶有數(shù)值的’next’事件,后面帶有’complete’或’error’。

(信號類似于其他語言/工具包中的“promise”(1),但更強大,因為它不僅限于向它的訂閱者一次只傳遞一個返回值. )

1、創(chuàng)建一個信號

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {

return nil;

}];

2、信號中添加訂閱者接收到的東西

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {

//以下為新加

NSString *str=[NSString stringWithFormat:@"https://www.baidu.com"];

NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

NSURLRequest *request = [NSURLRequest requestWithURL:url];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]init];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

[subscriber sendNext:@""];

[subscriber sendCompleted];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[subscriber sendError:error];

}];

[operation start];

//end

return nil;

}];

3、RACObserve()

這個宏是 RAC 中對 KVO 中那些悲慘的 API 的替代。 你只需要傳入對象和你想觀察的那個對象某屬性的 keypath.。給出這些參數(shù)后, RACObserve 會創(chuàng)建一個信號,一旦它有了訂閱者,,它就立刻發(fā)送那個屬性的當前值,并在發(fā)送那個屬性在這之后的任何變化。

RACSignal *signal1 = RACObserve(self. personModel,name);

//這行代碼的前提是你有一個personModel,personModel有一個name屬性

這僅是提供用于創(chuàng)建信號的一個工具. 這里有幾個立即可用的方式, 來從內(nèi)置控制流機制中拉取信號:

RACSignal *controlUpdate = [_myButtonrac_signalForControlEvents:UIControlEventTouchUpInside];

// signals for UIControl events send the control event value (UITextField, UIButton, UISlider, etc)

// subscribeNext:^(UIButton *button) { NSLog(@"%@", button); // UIButton instance }

RACSignal *textChange = [_myTextFieldrac_textSignal];

// some special methods are provided for commonly needed control event values off certain controls

// subscribeNext:^(UITextField *textfield) { NSLog(@"%@", _textfield.text); // "Hello!" }

RACSignal *alertButtonClicked = [_myAlertViewrac_buttonClickedSignal];

// signals for some delegate methods send the delegate params as the value

// e.g. UIAlertView, UIActionSheet, UIImagePickerControl, etc

// (limited to methods that return void)

// subscribeNext:^(NSNumber *buttonIndex) { NSLog(@"%@", buttonIndex); // "1" }

RACSignal *viewAppeared = [self rac_signalForSelector:@selector(viewDidAppear:)];

// signals for arbitrary selectors that return void, send the method params as the value

// works for built in or your own methods

// subscribeNext:^(NSNumber *animated) { NSLog(@"viewDidAppear %@", animated); // "viewDidAppear 1" }

什么是訂閱者?

簡言之,訂閱者就是一段代碼,它等待信號給它發(fā)送一些值,然后訂閱者就能處理這些值了. (它也可以作用于“complete”和“error”事件. )

簡述:理解為block,信號等同block調(diào)用?

RACSignal *usernameValidSignal = RACObserve(self. personModel,name);

// update the local property when this value changes

[usernameValidSignal subscribeNext: ^(NSNumber *isValidUserName) {

self.isValidName = isValidUserName.boolValue;

}];

以上代碼前提:controller 有一個personModel,有一個BOOL類型的isValidName,Model中有Number類型的isValidUserName

那問題來了,isValidName是BOOL為何我要傳NSNumber類型的。

答:RAC 只處理對象, 而不處理像 BOOL 這樣的原始值.。不過不用擔心,RAC 通常會幫你這些轉(zhuǎn)換。

RAC(self,isValidName) = RACObserve(self.personModel, isValidUserName);

//前面是target 后面是target下的@property

//用中文講,就是self.personModel的isValidUserName變化了,self.isValidName也要跟著變了。

那問題來了,self.isValidName做什么用,判斷嗎?那不就又繞回來了?把controller以前做判斷啊什么的邏輯交給viewmodel就好了,所以呢……

這樣我們可以把RACObserve(self.personModel, isValidUserName);綁定在textchange的協(xié)議方法中,或是確定按鈕的enable中,等等等等所有用這個值判斷的位置上(選位置時注意,不要總想在controller中操作)。

多個訂閱者, 副作用, 昂貴的操作

訂閱信號鏈時要明白重要的一件事是每當一個新值通過信號鏈被發(fā)送出去時, 實際上會給每個訂閱者都發(fā)送一次. 直到意識到這就我們而言是有意義的, 信號發(fā)出的值不存儲在任何地方(除了 RAC 在內(nèi)部實現(xiàn)中). 當信號需要發(fā)送一個新的值時, 它會遍歷所有的訂閱者并給每個訂閱者發(fā)送那個值. (這是對信號鏈實際工作的簡化說明, 但基本想法是對的)

這為什么重要?這意味著信號鏈某處存在的任何副作用, 任何影響應用世界的轉(zhuǎn)變, 將會發(fā)生多次. 這對新接觸 RAC 的用戶來說是意想不到的. (這也違反了函數(shù)式構(gòu)建的理念-數(shù)據(jù)輸入, 數(shù)據(jù)輸出).

一個做作的例子可能是: 信號鏈某處的信號在每次按鈕被按下時更新 self 中的一個計數(shù)器屬性. 如果信號鏈有多個訂閱者, 計數(shù)器的增長將會比你想的還要多. 你需要努力從信號鏈中盡可能剔除副作用. 當副作用不可避免時, 你可以使用一些恰當?shù)念A防機制. 我將會在另一篇文章中探索.

簡述:當存在多個訂閱者的時候,就像一對多廣播一樣,只要是訂閱者就會都遍歷一次。在設(shè)計之初就應該規(guī)范,不管是針對子viewModel的分別控制,還是條件限制,等等,

除副作用之外, 我們需要注意帶有昂貴操作和可變數(shù)據(jù)的信號鏈. 網(wǎng)絡請求就是一個三者兼得的例子:

網(wǎng)絡請求影響了應用的網(wǎng)絡層(副作用).

網(wǎng)絡請求為信號鏈引入了可變數(shù)據(jù). (兩個完全一樣請求可能返回了不同的數(shù)據(jù). )

網(wǎng)絡請求反應慢啊.

假設(shè)我根據(jù)一個text,text作為參數(shù),發(fā)起多個網(wǎng)絡請求,我所要的結(jié)果在網(wǎng)絡請求的結(jié)果中,那么多個訂閱者如何處理這個返回結(jié)果,下一篇介紹RACCommand

額外:自行百度-mock、method swizzling

(1)promise的概念

ES6原生提供了Promise對象。

所謂Promise,就是一個對象,用來傳遞異步操作的消息。它代表了某個未來才會知道結(jié)果的事件(通常是一個異步操作),并且這個事件提供統(tǒng)一的API,可供進一步處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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