1.ReactiveCocoa開發(fā)中常見用法有哪些?
第1種:代替代理
rac_signalForSelector:用于替代代理
// 1.代替代理,RACSubject
// RAC方法:可以判斷下某個方法有沒有調(diào)用
// 只要self調(diào)用Selector就會產(chǎn)生一個信號
// rac_signalForSelector:監(jiān)聽某個對象調(diào)用某個方法
[[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
NSLog(@"控制器調(diào)用了didReceiveMemoryWarning");
}];
// 判斷下redView有沒有調(diào)用btnClick,就表示點擊了按鈕
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"點擊了按鈕");
}];
第2種:代替KVO
rac_valuesAndChangesForKeyPath:用于監(jiān)聽某個對象的屬性改變
[_redView rac_observeKeyPath:@"name" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
// 只要監(jiān)聽的屬性一改變調(diào)用
NSLog(@"%@",_redView.name);
}];
// KVO:第二種,只要對象的值改變,就會產(chǎn)生信號,訂閱信號
[[_redView rac_valuesForKeyPath:@"name" observer:nil] subscribeNext:^(id x) {
}];
第3種:監(jiān)聽事件
rac_signalForControlEvents:用于監(jiān)聽某個事件
// 只要按鈕產(chǎn)生這個事件,就會產(chǎn)生一個信號
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按鈕被點擊%@",x);
}];
_btn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"按鈕點擊");
return [RACSignal empty];
}];
第4種:代替通知
rac_addObserverForName:用于監(jiān)聽某個通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
第5種:監(jiān)聽文本框文字改變
rac_textSignal:只要文本框發(fā)出改變就會發(fā)出這個信號
[_textField.rac_textSignal subscribeNext:^(id x) {
// x:文本框的文字
NSLog(@"%@",x);
}];
第6種:處理當(dāng)界面有多次請求時央勒,需要都獲取到數(shù)據(jù)時不见,才能展示界面
rac_liftSelector:withSignalsFromArray:Signals:當(dāng)傳入的Signals(信號數(shù)組),每一個signal都至少sendNext過一次崔步,就會去觸發(fā)第一個selector參數(shù)的方法
RACSignal *requestHot = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"請求最熱商品");
[subscriber sendNext:@"獲取最熱商品"];
return nil;
}];
RACSignal *requestNew = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"請求最新商品");
// [subscriber sendNext:@"獲取最新商品"];
return nil;
}];
// Selector調(diào)用:當(dāng)所有信號都發(fā)送數(shù)據(jù)的時候調(diào)用
// 數(shù)組存放信號
// Selector注意點:參數(shù)根據(jù)數(shù)組元素決定
// Selector方法參數(shù)類型,就是信號傳遞出來數(shù)據(jù)
[self rac_liftSelector:@selector(updateUI:data2:) withSignalsFromArray:@[requestHot,requestNew]];
}
// 只要兩個請求都請求完成的時候才會調(diào)用
- (void)updateUI:(NSString *)data1 data2:(NSString *)data2
{
NSLog(@"%@ %@",data1,data2);
}
2.ReactiveCocoa常見宏
第一種
RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于給某個對象的某個屬性綁定
// 給某個對象的某個屬性綁定一個信號,只要產(chǎn)生信號,就會把信號的內(nèi)容給對象的屬性賦值
// 給label的text屬性綁定一個信號
RAC(_label,text) = _texfField.rac_textSignal;
第二種
RACObserve(self, name):監(jiān)聽某個對象的某個屬性,返回的是信號
// 觀察某個對象某個屬性
[RACObserve(self, name) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
第三種
@weakify(Obj)和@strongify(Obj),一般兩個都是配套使用,解決循環(huán)引用問題
第四種
RACTuplePack:把數(shù)據(jù)包裝成RACTuple(元組類)
// RACTuplePack:快速把一些數(shù)據(jù)包裝成元組類
RACTuple *tuple = RACTuplePack(@"123",@1);
第五種
RACTupleUnpack:把RACTuple(元組類)解包成對應(yīng)的數(shù)據(jù)
// 參數(shù):需要解析生成出來變量名
RACTupleUnpack(NSString *str,NSNumber *num) = tuple;
NSLog(@"%@ %@",str,num);
3.ReactiveCocoa常見操作方法
ReactiveCocoa操作原理
所有的信號(RACSignal)都可以進行操作處理稳吮,因為所有操作方法都定義在RACStream.h中,因此只要繼承RACStream就有了操作處理方法
ReactiveCocoa操作思想
運用的是Hook(鉤子)思想井濒,Hook是一種用于改變API(應(yīng)用程序編程接口:方法)執(zhí)行結(jié)果的技術(shù). Hook用處:截獲API調(diào)用的技術(shù)灶似。 Hook原理:在每次調(diào)用一個API返回結(jié)果之前,先執(zhí)行你自己的方法瑞你,改變結(jié)果的輸出
ReactiveCocoa核心方法bind
ReactiveCocoa操作的核心方法是bind(綁定),而且RAC中核心開發(fā)方式酪惭,也是綁定,之前的開發(fā)方式是賦值者甲,而用RAC開發(fā)春感,應(yīng)該把重心放在綁定,也就是可以在創(chuàng)建一個對象的時候虏缸,就綁定好以后想要做的事情鲫懒,而不是等賦值之后在去做事情
核心方法bind的使用
RACSignal *bindSignal = [_textField.rac_textSignal bind:^RACStreamBindBlock{
// block調(diào)用時刻:只要一個信號被綁定就會調(diào)用.表示信號綁定完成
NSLog(@"源信號被綁定");
return ^RACStream *(id value, BOOL *stop){
// RACStreamBindBlock什么時候調(diào)用:每次源信號發(fā)出內(nèi)容,就會調(diào)用這個block
// value:源信號發(fā)出的內(nèi)容
NSLog(@"源信號發(fā)出的內(nèi)容:%@",value);
// RACStreamBindBlock作用:在這個block處理源信號的內(nèi)容
value = [NSString stringWithFormat:@"xmg%@",value];
// block返回值:信號(把處理完的值包裝成一個信號,返回出去)
// 創(chuàng)建一個信號,并且這個信號的傳遞的值是我們處理完的值,value
return [RACReturnSignal return:value];
};
}];
// 訂閱綁定信號,不在是源信號
[bindSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 執(zhí)行流程
/*
1.文字改變源信號
2.綁定源信號,[_textField.rac_textSignal bind]
* 調(diào)用bind返回綁定好的信號,didSubscribe
3.訂閱綁定信號
* 創(chuàng)建訂閱者
* 調(diào)用綁定信號的didSubscribe
4.執(zhí)行綁定信號didSubscribe
5.執(zhí)行bind方法傳入的block
6.訂閱源信號
7.只要源信號一發(fā)出內(nèi)容,就會調(diào)用id signal = bindingBlock(x, &stop);
* signal:把值處理完的信號
*/
ReactiveCocoa操作方法之映射(flattenMap,Map)
flattenMap:信號中信號,signalOfSignals
[[_textField.rac_textSignal flattenMap:^RACStream *(id value) {
// value:源信號的內(nèi)容
value = [NSString stringWithFormat:@"xmg%@",value];
// 返回值:信號,把處理完的值包裝成信號返回出去
return [RACReturnSignal return:value];
}] subscribeNext:^(id x) {
// 訂閱[RACReturnSignal return:value發(fā)送值
// x:綁定信號的值
NSLog(@"%@",x);
}];
map: 用于普通信號,信號發(fā)出普通值
[[_textField.rac_textSignal map:^id(id value) {
// value:源信號的內(nèi)容
// 返回值,就是處理源信號的內(nèi)容,直接返回
return [NSString stringWithFormat:@"----xmg%@",value];
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
FlatternMap和Map的區(qū)別
- 1.FlatternMap中的Block返回信號。
- 2.Map中的Block返回對象刽辙。
- 3.開發(fā)中窥岩,如果信號發(fā)出的值不是信號,映射一般使用Map
- 4.開發(fā)中宰缤,如果信號發(fā)出的值是信號颂翼,映射一般使用FlatternMap晃洒。
ReactiveCocoa操作方法之組合
concat:按一定順序拼接信號,當(dāng)多個信號發(fā)出的時候疚鲤,有順序的接收信號
// concat:連接信號,有順序的拼接,一定要等第一個信號完成的時候,第二個信號才會被激活
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
// 組合信號
RACSignal *signals = [signalA concat:signalB];
// 訂閱組合信號
[signals subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 發(fā)送數(shù)據(jù)
[signalA sendNext:@1];
[signalA sendCompleted];
[signalB sendNext:@2];
then:用于連接兩個信號锥累,當(dāng)?shù)谝粋€信號完成,才會連接then返回的信號
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
// 組合
RACSignal *signals = [signalA then:^RACSignal *{
return signalB;
}];
[signals subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signalA sendNext:@1];
[signalA sendCompleted];
[signalB sendNext:@2];
then跟concat區(qū)別:監(jiān)聽不到第一個信號的值,共同點都是必須第一個信號完成,第二個信號才會激活
merge: 把多個信號合并為一個信號集歇,任何一個信號有新值的時候就會調(diào)用
// merge:合并,任何一個信號只要發(fā)送值,就能訂閱
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
RACSignal *signals = [signalA merge:signalB];
[signals subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signalA sendNext:@1];
[signalB sendNext:@2];
[signalB sendNext:@3];
zipWith:把兩個信號壓縮成一個信號桶略,只有當(dāng)兩個信號同時發(fā)出信號內(nèi)容時,并且把兩個信號的內(nèi)容合并成一個元組诲宇,才會觸發(fā)壓縮流的next事件
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
RACSignal *signals = [signalA zipWith:signalB];
[signals subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// zipWith:當(dāng)兩個信號都發(fā)出內(nèi)容的時候,才能被訂閱到
[signalA sendNext:@1];
[signalB sendNext:@2];
[signalB sendNext:@3];
[signalA sendNext:@4];
combineLatest:將多個信號合并起來际歼,并且拿到各個信號的最新的值,必須每個合并的signal至少都有過一次sendNext,才會觸發(fā)合并的信號
// 第一個參數(shù):就是存放需要合并信號
[[RACSignal combineLatest:@[_textField1.rac_textSignal,_textField2.rac_textSignal] reduce:^id(NSString *str1,NSString *str2){
NSLog(@"%@ ---- %@",str1,str2);
// block:只要任意一個信號發(fā)出內(nèi)容,就會調(diào)用
// block參數(shù)個數(shù):由信號決定
// block參數(shù)類型:block的參數(shù)就是信號發(fā)出值
// 把兩個信號中的值聚合成哪個值
return @(str1.length && str2.length);
}] subscribeNext:^(id x) {
_btn.enabled = [x boolValue];
NSLog(@"%@",x);
}];
reduce聚合:用于信號發(fā)出的內(nèi)容是元組姑蓝,把信號發(fā)出元組的值聚合成一個值
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
// 聚合
// 常見的用法鹅心,(先組合在聚合)。combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock
// reduce中的block簡介:
// reduceblcok中的參數(shù)纺荧,有多少信號組合旭愧,reduceblcok就有多少參數(shù),每個參數(shù)就是之前信號發(fā)出的內(nèi)容
// reduceblcok的返回值:聚合信號之后的內(nèi)容宙暇。
RACSignal *reduceSignal = [RACSignal combineLatest:@[signalA,signalB] reduce:^id(NSNumber *num1 ,NSNumber *num2){
return [NSString stringWithFormat:@"%@ %@",num1,num2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
ReactiveCocoa操作方法之過濾
- filter:過濾信號输枯,使用它可以獲取滿足條件的信號
- ignore:忽略完某些值的信號
- distinctUntilChanged:當(dāng)上一次的值和當(dāng)前的值有明顯的變化就會發(fā)出信號,否則會被忽略掉
- take:從開始一共取N次的信號
- takeLast:取最后N次的信號,前提條件占贫,訂閱者必須調(diào)用完成桃熄,因為只有完成,就知道總共有多少信號
- takeUntil:(RACSignal *):獲取信號直到執(zhí)行完這個信號
- skip:(NSUInteger):跳過幾個信號,不接受
- switchToLatest:用于signalOfSignals(信號的信號)型奥,有時候信號也會發(fā)出信號瞳收,會在signalOfSignals中,獲取signalOfSignals發(fā)送的最新信號
ReactiveCocoa操作方法之秩序
- doNext: 執(zhí)行Next之前厢汹,會先執(zhí)行這個Block
- doCompleted: 執(zhí)行sendCompleted之前螟深,會先執(zhí)行這個Block
ReactiveCocoa操作方法之線程
- deliverOn: 內(nèi)容傳遞切換到制定線程中,副作用在原來線程中,把在創(chuàng)建信號時block中的代碼稱之為副作用
- subscribeOn: 內(nèi)容傳遞和副作用都會切換到制定線程中
ReactiveCocoa操作方法之時間
- timeout:超時烫葬,可以讓一個信號在一定的時間后,自動報錯
- interval 定時:每隔一段時間發(fā)出信號
- delay: 延遲發(fā)送next
ReactiveCocoa操作方法之重復(fù)
- retry重試 :只要失敗厘灼,就會重新執(zhí)行創(chuàng)建信號中的block,直到成功
- replay重放:當(dāng)一個信號被多次訂閱,反復(fù)播放內(nèi)容
- throttle節(jié)流:當(dāng)某個信號發(fā)送比較頻繁時夹纫,可以使用節(jié)流咽瓷,在某一段時間不發(fā)送信號內(nèi)容设凹,過了一段時間獲取信號的最新內(nèi)容發(fā)出
4.學(xué)習(xí)MVVM架構(gòu)思想
(1)程序為什么要架構(gòu)?
便于程序員開發(fā)和維護代碼
-
(2)常見的架構(gòu)思想有哪些茅姜?
- MVC ---- M:模型 V:視圖 C:控制器)
- MVVM ----M:模型 V:視圖+控制器 VM:視圖模型
- MVCS ---- M:模型 V:視圖 C:控制器 S:服務(wù)類
- VIPER ---- V:視圖 I:交互器 P:展示器 E:實體 R:路由
- (3)MVVM思想
- 模型(M):保存視圖數(shù)據(jù)
- 視圖+控制器(V):展示內(nèi)容 + 如何展示
- 視圖模型(VM):處理展示的業(yè)務(wù)邏輯闪朱,包括按鈕的點擊月匣,數(shù)據(jù)的請求和解析