StudyForRAC
study for https://github.com/shuaiwang007/RAC
If you have some questions, please tell me.
My email address is fanyang_32012@outlook.com.
RAC是一個非常強(qiáng)大的框架我們將會從以下方面去介紹它
推薦在學(xué)習(xí)前先看下這個項目,比較簡單也很好理解
- RACSignal
- RACSubject
- RACSequence
- RACMulticastConnection
- RACCommand
項目文件夾介紹
Lianxi 文件夾大致講述了RAC框架一些簡單的使用例子
the basis of RACSignal 文件夾主要講述了RACSignal這個類該如何去使用
the basis of RACSubject 文件夾主要講述了RACSubject與RACSignal的小區(qū)別,以及RACSubject如何作為代理去使用
the basis of RACCommand 文件夾主要講的是RACCommand如何使用,并監(jiān)聽完成情況
the skills of RAC 文件夾主要講的是RAC的使用技巧,主要包括UI控件addTarget的替代,代替代理,代替通知,代替KVO,監(jiān)聽事件,定時器
Signal processing 文件夾主要講的是信號的組合和處理
我們?yōu)槭裁匆獙W(xué)習(xí)RAC?
RAC是github團(tuán)隊開發(fā)的一套超重量級開源框架
目的在于事件的監(jiān)聽,RAC幾乎接管了Apple所有的事件機(jī)制,主要有以下六大點:
addTarget
代理
通知
KVO
時鐘
網(wǎng)絡(luò)異步回調(diào)
block不能列入其中的原因很簡單.block是提前準(zhǔn)備好的代碼,傳遞給接收方,至于什么時候執(zhí)行接收方并不知道
RAC學(xué)習(xí)起來的特點
- 學(xué)習(xí)起來比較難
- 團(tuán)隊開發(fā)的時候需要謹(jǐn)慎使用
- 團(tuán)隊代碼需要不斷的評審,保證團(tuán)隊中所有人代碼的風(fēng)格一致!避免閱讀代碼的困難
RAC框架如何pod導(dǎo)入項目
首先如果你不限制版本請在podfile里把use_frameworks!的注釋取消掉,即把#刪掉即可,因為RAC框架是支持Swift的
再然后可以添加上 pod 'ReactiveCocoa', '~> 2.5'
pod install即可
使用時只要將 'ReactiveCocoa.h' 'NSObject+RACKVOWrapper.h' 'RACReturnSignal.h' 這三個文件導(dǎo)入就可以了
注意:若出現(xiàn)大量報錯的話,請將Xcode升級至7.3以上
RAC框架的版本問題
4.0版本支持Swift2.0
3.0版本支持Swift1.2
2.5版本不支持Swift(Xcode7升級到Xcode8后由于swift版本變化有兩種辦法,一種是使用RAC2.5版本,一種就是在pod->target兼容swift選項)
若導(dǎo)入框架后出現(xiàn)報錯注意排查
RACSignal
-
首先在viewModel內(nèi)創(chuàng)建信號,外界在調(diào)用讀取信息方法時,向外界返回一個信號
-(RACSignal *)loadInfo{ return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { BOOL isError = NO; if (isError) { //發(fā)送錯誤信息 [subscriber sendError:[NSError errorWithDomain:@"github.com/SkyHarute" code:2333 userInfo:@{@"errorMessage":@"異常錯誤"}]]; } else { //創(chuàng)建信息(只需要知道是給_dataArray賦值就可以) [self creatInfo]; //若沒有錯誤發(fā)送正確信息,并將數(shù)組送出 [subscriber sendNext:_dataArray]; } //正確信息發(fā)送完畢后發(fā)送完成信號,若信息為錯誤信息則不發(fā)送完成信號 [subscriber sendCompleted]; return nil; }]; } -
在控制器調(diào)用該方法讀取信息獲取到當(dāng)前信號并訂閱
//這是signal對象方法中能把三種情況全部列舉出來的對象方法,根據(jù)需求決定,一般使用最簡單的就好 [[viewModel loadInfo] subscribeNext:^(id x) { //接收到正常發(fā)送信號,并打印信號傳過來的信息 NSLog(@"%@",x); } error:^(NSError *error) { //接收到錯誤信號,并打印出錯誤信息 NSLog(@"%@",error); } completed:^{ //接收到完成信號,并打印出完成信息,若為錯誤信號則不打印 NSLog(@"完成"); }]; 信號的三種對象方法sendNext,sendError,sendCompleted分別對應(yīng)訂閱者的next,error,completed三種情況,我們只要監(jiān)聽訂閱者的三個代碼塊,并寫上相應(yīng)的代碼,就可以實現(xiàn)在不同的代碼塊獲得自己想要的東西.
RAC在使用的時候由于系統(tǒng)提供的信號是始終存在的,所以在block中使用屬性或者成員變量幾乎都會涉及到一個循環(huán)引用的問題,有兩種方法可以解決,使用weakself解決或者RAC提供的weak-strong dance.用法也比較簡單:在 block 的外部使用 @weakify(self),在 block 的內(nèi)部使用 @strongify(self),具體的方法會在demo或下文中看到
列舉一些RAC常用的事件處理,這里教大家一個技巧,通過查看RAC框架中UI控件的分類便可以得知
-
按鈕點擊
@weakify(self); [[self.btn_event rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { @strongify(self); NSLog(@"%@",self.dataArray.firstObject); }]; -
textField輸入內(nèi)容的實時監(jiān)聽
[[self.tf_name rac_textSignal] subscribeNext:^(id x) { NSLog(@"%@",x); }]; -
組合信號的使用,我們想將兩個信號整合成一個信號的話這樣做就可以了,這樣就避免了同時訂閱兩個信號的苦惱
//信號組合獲取,注意將id類型改為RACTuple [[RACSignal combineLatest:@[self.tf_name.rac_textSignal,self.tf_age.rac_textSignal]] subscribeNext:^(RACTuple *x) { NSString * name = x.first; NSString * age = x.second; NSLog(@"name:%@,age:%@",name,age); }]; -
信號組合時reduce的使用
//根據(jù)textfield內(nèi)容決定按鈕是否可以點擊 // reduce 中,可以通過接收的參數(shù)進(jìn)行計算,并且返回需要的數(shù)值! [[RACSignal combineLatest:@[self.tf_name.rac_textSignal,self.tf_age.rac_textSignal] reduce:^id(NSString * name , NSString * age){ return @(name.length>0&&age.length>0); }] subscribeNext:^(id x) { @strongify(self); self.btn_event.enabled = [x boolValue]; }];
雙向綁定
一般雙向綁定是指UI控件和模型互相綁定的,一般是在在改變一個值的情況下另外一個對象也會改變,類似KVO,但KVO寫的時候很多觀察屬性寫在一個方法里對代碼的可閱讀性并不是很好
這里為了更好的體現(xiàn)出效果所以采用了textfield綁定到模型,模型綁定到label的做法,比較好理解,這樣在textfiled輸入文字便能夠?qū)崟r改變模型值,而模型值一旦改變,label的text內(nèi)容也會隨之改變.
-
直接雙向綁定
RACChannelTo(self.lb_name,text) = RACChannelTo(model, name); -
UI綁定模型
PersonModel * model = [[PersonModel alloc]init]; model = self.dataArray.firstObject; RAC(self.lb_name,text)=RACObserve(model, name); //這里不能使用基本數(shù)據(jù)類型,RAC中傳遞的都是id類型,使用基本類型會崩潰,所以使用map方法對返回值進(jìn)行了更替 RAC(self.lb_age,text)=[RACObserve(model, age) map:^id(id value) { return [value description]; }]; -
模型到UI
[[RACSignal combineLatest:@[self.tf_name.rac_textSignal,self.tf_age.rac_textSignal]] subscribeNext:^(RACTuple * x) { model.name = x.first; model.age = [x.second intValue]; }];
