關(guān)于ReactiveCocoa的比喻
“能夠把信號想象成水龍頭恭垦,僅僅只是里面不是水,而是玻璃球(value)晤斩,直徑跟水管的內(nèi)徑一樣,這樣就能保證玻璃球是依次排列姆坚。不會(huì)出現(xiàn)并排的情況(數(shù)據(jù)都是線性處理的澳泵,不會(huì)出現(xiàn)并發(fā)情況)。水龍頭的開關(guān)默認(rèn)是關(guān)的兼呵。除非有了接收方(subscriber)兔辅,才會(huì)打開。
這樣僅僅要有新的玻璃球進(jìn)來击喂,就會(huì)自己主動(dòng)傳送給接收方幢妄。
能夠在水龍頭上加一個(gè)過濾嘴(filter)。不符合的不讓通過茫负,也能夠加一個(gè)修改裝置,把球改變成符合自己的需求(map)乎赴。
也能夠把多個(gè)水龍頭合并成一個(gè)新的水龍頭(combineLatest:reduce:)忍法,這樣僅僅要當(dāng)中的一個(gè)水龍頭有玻璃球出來,這個(gè)新合并的水龍頭就會(huì)得到這個(gè)球榕吼。
1.RACSignal
#import <UIKit/UIKit.h>
@interface RACSignalController : UIViewController
@end
#import "RACSignalController.h"
@interface RACSignalController ()
@property (nonatomic, strong) id<RACSubscriber> subscriber;
@end
@implementation RACSignalController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"RACSignal";
/**
1. RACSiganl:信號類,一般表示將來有數(shù)據(jù)傳遞饿序,只要有數(shù)據(jù)改變,信號內(nèi)部接收到數(shù)據(jù)羹蚣,就會(huì)馬上發(fā)出數(shù)據(jù)原探。
信號類(RACSiganl),只是表示當(dāng)數(shù)據(jù)改變時(shí)顽素,信號內(nèi)部會(huì)發(fā)出數(shù)據(jù)咽弦,它本身不具備發(fā)送信號的能力,而是交給內(nèi)部一個(gè)訂閱者去發(fā)出胁出。
2. 默認(rèn)一個(gè)信號都是冷信號型型,也就是值改變了,也不會(huì)觸發(fā)全蝶,只有訂閱了這個(gè)信號闹蒜,這個(gè)信號才會(huì)變?yōu)闊嵝盘査峦鳎蹈淖兞瞬艜?huì)觸發(fā)。
3. 如何訂閱信號:調(diào)用信號RACSignal的subscribeNext就能訂閱绷落。
*/
// 核心:信號類
// 信號類作用:只要有數(shù)據(jù)改變姥闪,就會(huì)把數(shù)據(jù)包裝成一個(gè)信號,傳遞出去砌烁。
// 只要有數(shù)據(jù)改變筐喳,就會(huì)有信號發(fā)出。
// 數(shù)據(jù)發(fā)出往弓,并不是信號類發(fā)出疏唾。
// 1.創(chuàng)建信號 createSignal:didSubscribe(block)
// RACDisposable:取消訂閱
// RACSubscriber:發(fā)送數(shù)據(jù)
// createSignal方法:
// 1.創(chuàng)建RACDynamicSignal
// 2.把didSubscribe保存到RACDynamicSignal
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// block調(diào)用時(shí)刻:當(dāng)信號被訂閱的時(shí)候就會(huì)調(diào)用
// block作用:描述當(dāng)前信號哪些數(shù)據(jù)需要發(fā)送
// 3.發(fā)送信號
NSLog(@"調(diào)用了didSubscribe");
// 通常:傳遞數(shù)據(jù)出去
[subscriber sendNext:@"發(fā)送信號"];
/**
如果不在發(fā)送數(shù)據(jù),最好發(fā)送信號完成函似,內(nèi)部會(huì)自動(dòng)調(diào)用[RACDisposable disposable]取消訂閱信號
*/
[subscriber sendCompleted];
// 取消訂閱方法
return [RACDisposable disposableWithBlock:^{
// 信號什么時(shí)候被取消:1.自動(dòng)取消槐脏,當(dāng)一個(gè)信號的訂閱者被銷毀的時(shí)候,就會(huì)自動(dòng)取消訂閱 2.主動(dòng)取消
// block調(diào)用時(shí)刻:一旦一個(gè)信號撇寞,被取消訂閱的時(shí)候就會(huì)調(diào)用
// block作用:當(dāng)信號取消訂閱顿天,用于清空一些資源
NSLog(@"信號銷毀了");
}];
}];
// 2.訂閱信號
[signal subscribeNext:^(id x) {
NSLog(@"訂閱信號:%@",x);
}];
//輸出
//訂閱信號:發(fā)送信號
//信號銷毀了
/**
RACSignal底層實(shí)現(xiàn)
1. 創(chuàng)建信號,首先把didSubscribe保存到信號中蔑担,還不會(huì)觸發(fā)牌废。
2. 當(dāng)信號被訂閱,也就是調(diào)用signal的subscribeNext:nextBlock
2.1 subscribeNext內(nèi)部會(huì)調(diào)用siganl的didSubscribe
2.2 subscribeNext內(nèi)部會(huì)創(chuàng)建訂閱者subscriber啤握,并且把nextBlock保存到subscriber中
3.0 siganl的didSubscribe中調(diào)用[subscriber sendNext:@"發(fā)送信號"];
3.1 sendNext底層其實(shí)就是執(zhí)行subscriber的nextBlock
*/
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
/**
有一個(gè)全局變量保存值就不會(huì)走下面取消訂閱方法:現(xiàn)在有問題
*/
self.subscriber = subscriber;
[subscriber sendNext:@"123"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"走銷毀這個(gè)方法了");
}];
}];
//訂閱信號返回RACDisposable
RACDisposable *disposable = [signal1 subscribeNext:^(id x) {
NSLog(@"接收打印的值:%@",x);
}];
// 默認(rèn)一個(gè)信號發(fā)送數(shù)據(jù)完畢們就會(huì)主動(dòng)取消訂閱.
// 只要訂閱者在,就不會(huì)自動(dòng)取消信號訂閱
// 手動(dòng)取消訂閱者
[disposable dispose];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
2.RACSubscriber
#import <UIKit/UIKit.h>
@interface RACSubscriberController : UIViewController
@end
#import "RACSubscriberController.h"
#import "RedView.h"
@interface RACSubscriberController ()
@end
@implementation RACSubscriberController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"RACSubscriber";
/**
1. RACSubscriber: 表示訂閱者的意思鸟缕,用于發(fā)送信號,這是一個(gè)協(xié)議排抬,不是一個(gè)類懂从,只要遵守這個(gè)協(xié)議,并且實(shí)現(xiàn)方法才能成為訂閱者蹲蒲。通過create創(chuàng)建的信號番甩,都有一個(gè)訂閱者,幫助他發(fā)送數(shù)據(jù)届搁。
2. RACDisposable:用于取消訂閱或者清理資源缘薛,當(dāng)信號發(fā)送完成或者發(fā)送錯(cuò)誤的時(shí)候,就會(huì)自動(dòng)觸發(fā)它卡睦。
使用場景:不想監(jiān)聽某個(gè)信號時(shí)宴胧,可以通過它主動(dòng)取消訂閱信號。
3. RACSubject:RACSubject:信號提供者表锻,自己可以充當(dāng)信號牺汤,又能發(fā)送信號。
使用場景:通常用來代替代理浩嫌,有了它檐迟,就不必要定義代理了补胚。
4. RACReplaySubject:重復(fù)提供信號類,RACSubject的子類追迟。
RACReplaySubject與RACSubject區(qū)別:
RACReplaySubject可以先發(fā)送信號溶其,在訂閱信號,RACSubject就不可以敦间。
使用場景一:如果一個(gè)信號每被訂閱一次瓶逃,就需要把之前的值重復(fù)發(fā)送一遍,使用重復(fù)提供信號類廓块。
使用場景二:可以設(shè)置capacity數(shù)量來限制緩存的value的數(shù)量,即只緩充最新的幾個(gè)值厢绝。
*/
// RACSubject使用
[self RACSubjectUse];
// RACReplaySubject使用
[self RACReplaySubjectUse];
// RACSubject替換代理使用
[self RACSubjectReplaceAgent];
}
#pragma mark - RACSubjectUse
- (void)RACSubjectUse {
// RACSubject使用步驟
// 1.創(chuàng)建信號 [RACSubject subject],跟RACSiganl不一樣带猴,創(chuàng)建信號時(shí)沒有block昔汉。
// 2.訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.發(fā)送信號 sendNext:(id)value
// 1.創(chuàng)建信號
RACSubject *subject = [RACSubject subject];
// 2.訂閱信號
[subject subscribeNext:^(id x) {
//當(dāng)信號發(fā)出新值,就會(huì)調(diào)用.
NSLog(@"第一個(gè)訂閱者%@",x);
}];
[subject subscribeNext:^(id x) {
NSLog(@"第二個(gè)訂閱者%@",x);
}];
// 3.發(fā)送信號
[subject sendNext:@"123456"];
// 4.發(fā)送信號完成,內(nèi)部會(huì)自動(dòng)取消訂閱者
[subject sendCompleted];
// 輸出:
// 第一個(gè)訂閱者123456
// 第二個(gè)訂閱者123456
}
#pragma mark - RACReplaySubjectUse
-(void)RACReplaySubjectUse {
// RACReplaySubject使用步驟:
// 1.創(chuàng)建信號 [RACSubject subject]拴清,跟RACSiganl不一樣靶病,創(chuàng)建信號時(shí)沒有block。
// 2.可以先訂閱信號口予,也可以先發(fā)送信號娄周。
// 2.1 訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 2.2 發(fā)送信號 sendNext:(id)value
// RACReplaySubject:底層實(shí)現(xiàn)和RACSubject不一樣。
// 1.調(diào)用sendNext發(fā)送信號沪停,把值保存起來煤辨,然后遍歷剛剛保存的所有訂閱者,一個(gè)一個(gè)調(diào)用訂閱者的nextBlock木张。
// 2.調(diào)用subscribeNext訂閱信號掷酗,遍歷保存的所有值,一個(gè)一個(gè)調(diào)用訂閱者的nextBlock
// 1.創(chuàng)建信號
RACReplaySubject *replaySubject = [RACReplaySubject subject];
// 2.發(fā)送信號
[replaySubject sendNext:@"1"];
[replaySubject sendNext:@"2"];
// 3.訂閱信號
[replaySubject subscribeNext:^(id x) {
NSLog(@"第一個(gè)訂閱者接收到的數(shù)據(jù)%@",x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"第二個(gè)訂閱者接收到的數(shù)據(jù)%@",x);
}];
// 輸出:
// 第一個(gè)訂閱者接收到的數(shù)據(jù)1
// 第一個(gè)訂閱者接收到的數(shù)據(jù)2
// 第二個(gè)訂閱者接收到的數(shù)據(jù)1
// 第二個(gè)訂閱者接收到的數(shù)據(jù)2
}
#pragma mark - RACSubject替換代理
- (void)RACSubjectReplaceAgent {
RedView *redView = [[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:nil options:nil] lastObject];
redView.frame = CGRectMake(0, 64, 300, 200);
redView.center = self.view.center;
[redView.btnClickSignal subscribeNext:^(id x) {
NSLog(@"---%@--",x);
}];
[self.view addSubview:redView];
}
@end
3.RAC集合
#import <UIKit/UIKit.h>
@interface RACSetViewController : UIViewController
@end
#import "RACSetViewController.h"
#import "Flag.h"
@interface RACSetViewController ()
@end
@implementation RACSetViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self tuple];
[self array];
[self dictionary];
[self initWithDictionary];
}
#pragma mark- RACTuple數(shù)組
- (void)tuple {
/**
RACTuple:元組類,類似NSArray,用來包裝值.
*/
//元組
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"345",@1]];
NSString *first = tuple[0];
NSLog(@"%@",first);
//輸出:
//123
}
#pragma mark- RACSequence數(shù)組
- (void)array {
// 數(shù)組
NSArray *arr = @[@"213",@"321",@1];
//RAC 集合
RACSequence *sequence = arr.rac_sequence;
// 把集合轉(zhuǎn)換成信號
RACSignal *signal = sequence.signal;
//訂閱集合信號,內(nèi)部會(huì)自動(dòng)遍歷所有的元素發(fā)出來
[signal subscribeNext:^(id x) {
NSLog(@"遍歷數(shù)組%@",x);
}];
//輸出:
/**
遍歷數(shù)組213
遍歷數(shù)組321
遍歷數(shù)組1
*/
//高級寫法
[arr.rac_sequence.signal subscribeNext:^(id x) {
NSLog(@"高級寫法遍歷數(shù)組打印%@",x);
}];
//輸出:
/**
高級寫法遍歷數(shù)組打印213
高級寫法遍歷數(shù)組打印321
高級寫法遍歷數(shù)組打印1
*/
}
#pragma mark- RACTuple數(shù)組
- (void)dictionary {
// 字典
NSDictionary *dict = @{@"sex":@"女",@"name":@"蒼老師",@"age":@18};
//轉(zhuǎn)換成集合
[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
// NSString *key = x[0];
// NSString *value = x[1];
// NSLog(@"%@ %@",key,value);
// RACTupleUnpack:用來解析元組
// 宏里面的參數(shù),傳需要解析出來的變量名
//= 右邊,放需要解析的元組
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@ %@",key,value);
}];
//輸出:
/**
sex 女
name 蒼老師
age 18
*/
}
#pragma mark- 字典轉(zhuǎn)模型
- (void)initWithDictionary {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
// NSMutableArray *arr = [NSMutableArray array];
// // rac_sequence注意點(diǎn):調(diào)用subscribeNext窟哺,并不會(huì)馬上執(zhí)行nextBlock,而是會(huì)等一會(huì)技肩。
// [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) {
// Flag *flag = [Flag flagWithDict:x];
// [arr addObject:flag];
// }];
//高級用法
// map:映射的意思且轨,目的:把原始值value映射成一個(gè)新值
// array: 把集合轉(zhuǎn)換成數(shù)組
// 底層實(shí)現(xiàn):當(dāng)信號被訂閱,會(huì)遍歷集合中的原始值虚婿,映射成新值旋奢,并且保存到新的數(shù)組里。
NSArray *arr = [[dictArr.rac_sequence map:^id(NSDictionary *value) {
return [Flag flagWithDict:value];
}] array];
NSLog(@"%@",arr);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
4.RACMulticastConnection
#import <UIKit/UIKit.h>
@interface RACMulticastConnectionController : UIViewController
@end
#import "RACMulticastConnectionController.h"
@interface RACMulticastConnectionController ()
@end
@implementation RACMulticastConnectionController
- (void)viewDidLoad {
[super viewDidLoad];
/**
RACMulticastConnection:用于當(dāng)一個(gè)信號然痊,被多次訂閱時(shí)至朗,為了保證創(chuàng)建信號時(shí),避免多次調(diào)用創(chuàng)建信號中的block剧浸,造成副作用锹引,可以使用這個(gè)類處理矗钟。
使用注意:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創(chuàng)建.
*/
[self RACMulticastConnection];
}
- (void)RACMulticastConnection {
//RACMulticastConnection簡單使用:
// RACMulticastConnection使用步驟:
// 1.創(chuàng)建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
// 2.創(chuàng)建連接 RACMulticastConnection *connect = [signal publish];
// 3.訂閱信號,注意:訂閱的不在是之前的信號,而是連接的信號嫌变。 [connect.signal subscribeNext:nextBlock]
// 4.連接 [connect connect]
// RACMulticastConnection底層原理:
// 1.創(chuàng)建connect吨艇,connect.sourceSignal -> RACSignal(原始信號) connect.signal -> RACSubject
// 2.訂閱connect.signal,會(huì)調(diào)用RACSubject的subscribeNext腾啥,創(chuàng)建訂閱者东涡,而且把訂閱者保存起來,不會(huì)執(zhí)行block倘待。
// 3.[connect connect]內(nèi)部會(huì)訂閱RACSignal(原始信號)疮跑,并且訂閱者是RACSubject
// 3.1.訂閱原始信號,就會(huì)調(diào)用原始信號中的didSubscribe
// 3.2 didSubscribe凸舵,拿到訂閱者調(diào)用sendNext祖娘,其實(shí)是調(diào)用RACSubject的sendNext
// 4.RACSubject的sendNext,會(huì)遍歷RACSubject所有訂閱者發(fā)送信號。
// 4.1 因?yàn)閯倓偟诙秸昙洌际窃谟嗛哛ACSubject贿条,因此會(huì)拿到第二步所有的訂閱者,調(diào)用他們的nextBlock
// 需求:假設(shè)在一個(gè)信號中發(fā)送請求增热,每次訂閱一次都會(huì)發(fā)送請求整以,這樣就會(huì)導(dǎo)致多次請求。
// 解決:使用RACMulticastConnection就能解決.
// 1.創(chuàng)建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"發(fā)送請求");
[subscriber sendNext:@"1"];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 2.訂閱信號
[signal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
[signal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 3.運(yùn)行結(jié)果峻仇,會(huì)執(zhí)行兩遍發(fā)送請求公黑,也就是每次訂閱都會(huì)發(fā)送一次請求
// RACMulticastConnection:解決重復(fù)請求問題
// 1.創(chuàng)建信號
RACSignal *connectionSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"發(fā)送請求--");
[subscriber sendNext:@1];
return [RACDisposable disposableWithBlock:^{
}];
}];
//2.創(chuàng)建連接
RACMulticastConnection *connect = [connectionSignal publish];
//3.訂閱信號
// 注意:訂閱信號伙窃,也不能激活信號荣德,只是保存訂閱者到數(shù)組,必須通過連接,當(dāng)調(diào)用連接耻蛇,就會(huì)一次性調(diào)用所有訂閱者的sendNext:
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者一信號--");
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者二信號--");
}];
//4.連接,激活信號
[connect connect];
//輸出:
/**
發(fā)送請求--
訂閱者一信號--
訂閱者二信號--
*/
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
5.RACCommand
#import <UIKit/UIKit.h>
@interface RACCommandController : UIViewController
@end
#import "RACCommandController.h"
@interface RACCommandController ()
@property (nonatomic, strong) RACCommand *command;
@end
@implementation RACCommandController
- (void)viewDidLoad {
[super viewDidLoad];
/**
RACCommand:RAC中用于處理事件的類吭从,可以把事件如何處理,事件中的數(shù)據(jù)如何傳遞朝蜘,包裝到這個(gè)類中,他可以很方便的監(jiān)控事件的執(zhí)行過程涩金。
使用場景:監(jiān)聽按鈕點(diǎn)擊谱醇,網(wǎng)絡(luò)請求
*/
[self RACCommandUse];
[self switchToLatest];
[self commandData];
}
- (void)RACCommandUse {
// 一、RACCommand使用步驟:
// 1.創(chuàng)建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
// 2.在signalBlock中步做,創(chuàng)建RACSignal副渴,并且作為signalBlock的返回值
// 3.執(zhí)行命令 - (RACSignal *)execute:(id)input
// 二、RACCommand使用注意:
// 1.signalBlock必須要返回一個(gè)信號全度,不能傳nil.
// 2.如果不想要傳遞信號煮剧,直接創(chuàng)建空的信號[RACSignal empty];
// 3.RACCommand中信號如果數(shù)據(jù)傳遞完,必須調(diào)用[subscriber sendCompleted],這時(shí)命令才會(huì)執(zhí)行完畢勉盅,否則永遠(yuǎn)處于執(zhí)行中佑颇。
// 三、RACCommand設(shè)計(jì)思想:內(nèi)部signalBlock為什么要返回一個(gè)信號菇篡,這個(gè)信號有什么用漩符。
// 1.在RAC開發(fā)中,通常會(huì)把網(wǎng)絡(luò)請求封裝到RACCommand驱还,直接執(zhí)行某個(gè)RACCommand就能發(fā)送請求嗜暴。
// 2.當(dāng)RACCommand內(nèi)部請求到數(shù)據(jù)的時(shí)候,需要把請求的數(shù)據(jù)傳遞給外界议蟆,這時(shí)候就需要通過signalBlock返回的信號傳遞了闷沥。
// 四、如何拿到RACCommand中返回信號發(fā)出的數(shù)據(jù)咐容。
// 1.RACCommand有個(gè)執(zhí)行信號源executionSignals舆逃,這個(gè)是signal of signals(信號的信號),意思是信號發(fā)出的數(shù)據(jù)是信號,不是普通的類型戳粒。
// 2.訂閱executionSignals就能拿到RACCommand中返回的信號路狮,然后訂閱signalBlock返回的信號,就能獲取發(fā)出的值蔚约。
// 五奄妨、監(jiān)聽當(dāng)前命令是否正在執(zhí)行executing
// 六、使用場景,監(jiān)聽按鈕點(diǎn)擊苹祟,網(wǎng)絡(luò)請求
// 1.創(chuàng)建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"執(zhí)行命令");
// 創(chuàng)建空信號,必須返回信號
// return [RACSignal empty];
// 2.創(chuàng)建信號,用來傳遞數(shù)據(jù)
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"請求數(shù)據(jù)"];
// 注意:數(shù)據(jù)傳遞完砸抛,最好調(diào)用sendCompleted树枫,這時(shí)命令才執(zhí)行完畢直焙。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"數(shù)據(jù)銷毀");
}];
}];
}];
// 強(qiáng)引用命令,不要被銷毀砂轻,否則接收不到數(shù)據(jù)
_command = command;
// 監(jiān)聽事件有沒有完成
[command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) { // 當(dāng)前正在執(zhí)行
NSLog(@"當(dāng)前正在執(zhí)行");
}else{
// 執(zhí)行完成/沒有執(zhí)行
NSLog(@"執(zhí)行完成/沒有執(zhí)行");
}
}];
// 獲取信號中信號發(fā)送的最新信號
[self.command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 執(zhí)行命令
//[self.command execute:@1];
}
// RAC高級用法
- (void)switchToLatest {
//創(chuàng)建信號中信號
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
// 訂閱信號
// [signalOfSignals subscribeNext:^(RACSignal *x) {
// [x subscribeNext:^(id x) {
// NSLog(@"%@",x);
// }];
// }];
// switchToLatest:獲取信號中信號發(fā)送的最新信號
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 發(fā)送信號
[signalOfSignals sendNext:signalA];
[signalA sendNext:@1];
[signalB sendNext:@"BB"];
[signalA sendNext:@"11"];
}
- (void)commandData
{
// RACCommand:處理事件
// RACCommand:不能返回一個(gè)空的信號
// 1.創(chuàng)建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
// input:執(zhí)行命令傳入?yún)?shù)
// Block調(diào)用:執(zhí)行命令的時(shí)候就會(huì)調(diào)用
NSLog(@"input-%@",input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送數(shù)據(jù)
[subscriber sendNext:@"執(zhí)行命令產(chǎn)生的數(shù)據(jù)"];
return nil;
}];
}];
// 如何拿到執(zhí)行命令中產(chǎn)生的數(shù)據(jù)
// 訂閱命令內(nèi)部的信號
// 1.方式一:直接訂閱執(zhí)行命令返回的信號
// 2.方式二:
// 2.執(zhí)行命令
RACSignal *signal = [command execute:@1];
// 3.訂閱信號
[signal subscribeNext:^(id x) {
NSLog(@"x-%@",x);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
6.RAC常用方法--常見宏
@interface RACMethodUseViewController : UIViewController
@end
#import "RACMethodUseViewController.h"
#import "RedView.h"
@interface RACMethodUseViewController ()
@end
@implementation RACMethodUseViewController
- (void)viewDidLoad {
[super viewDidLoad];
#pragma mark -常見的五個(gè)宏
////常見的五個(gè)宏
//使用宏定義要單獨(dú)導(dǎo)入 #import <RACEXTScope.h>
// 1:
/*
RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于給某個(gè)對象的某個(gè)屬性綁定信號
只要文本框文字改變奔誓,就會(huì)修改label的文字
RAC(self.labelView,text) = _textField.rac_textSignal;
*/
// 2:
/*
RACObserve(self, name):監(jiān)聽某個(gè)對象的某個(gè)屬性,返回的是信號。
[RACObserve(self.view, center) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
*/
//當(dāng)RACObserve放在block里面使用時(shí)一定要加上weakify搔涝,不管里面有沒有使用到self厨喂;否則會(huì)內(nèi)存泄漏,因?yàn)镽ACObserve宏里面就有一個(gè)self
/*
@weakify(self);
RACSignal *signal3 = [anotherSignal flattenMap:^(NSArrayController *arrayController) {
Avoids a retain cycle because of RACObserve implicitly referencing self
@strongify(self);
return RACObserve(arrayController, items);
}];
*/
//3:
//@weakify(Obj)和@strongify(Obj),一般兩個(gè)都是配套使用,在主頭文件(ReactiveCocoa.h)中并沒有導(dǎo)入体谒,需要自己手動(dòng)導(dǎo)入,RACEXTScope.h才可以使用臼婆。但是每次導(dǎo)入都非常麻煩抒痒,只需要在主頭文件自己導(dǎo)入就好了
// 4:
/*
RACTuplePack:把數(shù)據(jù)包裝成RACTuple(元組類)
把參數(shù)中的數(shù)據(jù)包裝成元組
RACTuple *tuple = RACTuplePack(@10,@20);
*/
//5:
/*
RACTupleUnpack:把RACTuple(元組類)解包成對應(yīng)的數(shù)據(jù)
把參數(shù)中的數(shù)據(jù)包裝成元組
RACTuple *tuple = RACTuplePack(@"xmg",@20);
解包元組,會(huì)把元組的值颁褂,按順序給參數(shù)里面的變量賦值
name = @"xmg" age = @20
RACTupleUnpack(NSString *name,NSNumber *age) = tuple;
*/
[self initView];
}
- (void)initView {
self.navigationItem.title = @"RAC常用方法";
self.view.backgroundColor = [UIColor whiteColor];
#pragma mark -監(jiān)聽按鈕的點(diǎn)擊事件
// 1.監(jiān)聽按鈕的點(diǎn)擊事件
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(100, 100, 80, 40);
[button setTitle:@"點(diǎn)擊事件" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor redColor]];
[self.view addSubview:button];
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按鈕被點(diǎn)擊了");
}];
#pragma mark -代理的使用
// 2.代理的使用
// 2.1 只要傳值,就必須使用RACSubject
RedView *redView = [[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:nil options:nil] lastObject];
redView.frame = CGRectMake(0, 140, self.view.bounds.size.width, 200);
[self.view addSubview:redView];
[redView.btnClickSignal subscribeNext:^(id x) {
NSLog(@"---點(diǎn)擊按鈕了,觸發(fā)了事件");
}];
// 2.2把控制器調(diào)用didReceiveMemoryWarning轉(zhuǎn)換成信號
// rac_signalForSelector:監(jiān)聽某對象有沒有調(diào)用某方法
[[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
NSLog(@"控制器調(diào)用didReceiveMemoryWarning");
}];
#pragma mark -KVO
// 3.KVO
// 把監(jiān)聽redV的center屬性改變轉(zhuǎn)換成信號故响,只要值改變就會(huì)發(fā)送信號
// observer:可以傳入nil
[[redView rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
NSLog(@"center:%@",x);
}];
#pragma mark -代替通知
// 4.代替通知
UITextField *textfield = [[UITextField alloc] initWithFrame:CGRectMake(100, 340, 150, 40)];
textfield.placeholder = @"監(jiān)聽鍵盤的彈起";
textfield.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:textfield];
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"監(jiān)聽鍵盤的高度:%@",x);
}];
#pragma mark -監(jiān)聽文本框的文字改變
// 5.監(jiān)聽文本框的文字改變
[textfield.rac_textSignal subscribeNext:^(id x) {
NSLog(@"輸入框中文字改變了---%@",x);
}];
#pragma mark -處理多個(gè)請求傀广,都返回結(jié)果的時(shí)候,統(tǒng)一做處理.
// 6.處理多個(gè)請求彩届,都返回結(jié)果的時(shí)候伪冰,統(tǒng)一做處理.
RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送請求1
[subscriber sendNext:@"發(fā)送請求1"];
return nil;
}];
RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送請求2
[subscriber sendNext:@"發(fā)送請求2"];
return nil;
}];
// 使用注意:幾個(gè)信號,參數(shù)一的方法就幾個(gè)參數(shù)樟蠕,每個(gè)參數(shù)對應(yīng)信號發(fā)出的數(shù)據(jù)贮聂。
[self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
}
// 更新UI
- (void)updateUIWithR1:(id)data r2:(id)data1
{
NSLog(@"更新UI%@ %@",data,data1);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
7.RAC操作方法一
#import <UIKit/UIKit.h>
@interface RACOperationMethodController : UIViewController
@end
//1.ReactiveCocoa常見操作方法介紹。
/**
1.1 ReactiveCocoa操作須知
所有的信號(RACSignal)都可以進(jìn)行操作處理寨辩,因?yàn)樗胁僮鞣椒ǘ级x在RACStream.h中吓懈,而RACSignal繼承RACStream。
1.2 ReactiveCocoa操作思想
運(yùn)用的是Hook(鉤子)思想靡狞,Hook是一種用于改變API(應(yīng)用程序編程接口:方法)執(zhí)行結(jié)果的技術(shù).
Hook用處:截獲API調(diào)用的技術(shù)耻警。
Hook原理:在每次調(diào)用一個(gè)API返回結(jié)果之前,先執(zhí)行你自己的方法甸怕,改變結(jié)果的輸出甘穿。
RAC開發(fā)方式:RAC中核心開發(fā)方式,也是綁定梢杭,之前的開發(fā)方式是賦值温兼,而用RAC開發(fā),應(yīng)該把重心放在綁定式曲,也就是可以在創(chuàng)建一個(gè)對象的時(shí)候妨托,就綁定好以后想要做的事情,而不是等賦值之后在去做事情吝羞。
列如:把數(shù)據(jù)展示到控件上兰伤,之前都是重寫控件的setModel方法,用RAC就可以在一開始創(chuàng)建控件的時(shí)候钧排,就綁定好數(shù)據(jù)敦腔。
1.3 ReactiveCocoa核心方法bind
ReactiveCocoa操作的核心方法是bind(綁定),給RAC中的信號進(jìn)行綁定,只要信號一發(fā)送數(shù)據(jù)恨溜,就能監(jiān)聽到符衔,從而把發(fā)送數(shù)據(jù)改成自己想要的數(shù)據(jù)。
在開發(fā)中很少使用bind方法糟袁,bind屬于RAC中的底層方法判族,RAC已經(jīng)封裝了很多好用的其他方法,底層都是調(diào)用bind项戴,用法比bind簡單.
bind方法簡單介紹和使用形帮。
*/
/**
// 假設(shè)想監(jiān)聽文本框的內(nèi)容,并且在每次輸出結(jié)果的時(shí)候,都在文本框的內(nèi)容拼接一段文字“輸出:”
// 方式一:在返回結(jié)果后辩撑,拼接界斜。
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"輸出:%@",x);
}];
// 方式二:在返回結(jié)果前,拼接合冀,使用RAC中bind方法做處理各薇。
// bind方法參數(shù):需要傳入一個(gè)返回值是RACStreamBindBlock的block參數(shù)
// RACStreamBindBlock是一個(gè)block的類型,返回值是信號君躺,參數(shù)(value,stop)峭判,因此參數(shù)的block返回值也是一個(gè)block。
// RACStreamBindBlock:
// 參數(shù)一(value):表示接收到信號的原始值晰洒,還沒做處理
// 參數(shù)二(*stop):用來控制綁定Block朝抖,如果*stop = yes,那么就會(huì)結(jié)束綁定。
// 返回值:信號谍珊,做好處理治宣,在通過這個(gè)信號返回出去,一般使用RACReturnSignal,需要手動(dòng)導(dǎo)入頭文件RACReturnSignal.h砌滞。
// bind方法使用步驟:
// 1.傳入一個(gè)返回值RACStreamBindBlock的block侮邀。
// 2.描述一個(gè)RACStreamBindBlock類型的bindBlock作為block的返回值。
// 3.描述一個(gè)返回結(jié)果的信號贝润,作為bindBlock的返回值绊茧。
// 注意:在bindBlock中做信號結(jié)果的處理。
// 底層實(shí)現(xiàn):
// 1.源信號調(diào)用bind,會(huì)重新創(chuàng)建一個(gè)綁定信號打掘。
// 2.當(dāng)綁定信號被訂閱华畏,就會(huì)調(diào)用綁定信號中的didSubscribe,生成一個(gè)bindingBlock尊蚁。
// 3.當(dāng)源信號有內(nèi)容發(fā)出亡笑,就會(huì)把內(nèi)容傳遞到bindingBlock處理,調(diào)用bindingBlock(value,stop)
// 4.調(diào)用bindingBlock(value,stop)横朋,會(huì)返回一個(gè)內(nèi)容處理完成的信號(RACReturnSignal)仑乌。
// 5.訂閱RACReturnSignal,就會(huì)拿到綁定信號的訂閱者琴锭,把處理完成的信號內(nèi)容發(fā)送出來晰甚。
// 注意:不同訂閱者,保存不同的nextBlock决帖,看源碼的時(shí)候厕九,一定要看清楚訂閱者是哪個(gè)。
// 這里需要手動(dòng)導(dǎo)入#import <ReactiveCocoa/RACReturnSignal.h>地回,才能使用RACReturnSignal扁远。
[[_textField.rac_textSignal bind:^RACStreamBindBlock{
// 什么時(shí)候調(diào)用:
// block作用:表示綁定了一個(gè)信號.
return ^RACStream *(id value, BOOL *stop){
// 什么時(shí)候調(diào)用block:當(dāng)信號有新的值發(fā)出腺阳,就會(huì)來到這個(gè)block。
// block作用:做返回值的處理
// 做好處理穿香,通過信號返回出去.
return [RACReturnSignal return:[NSString stringWithFormat:@"輸出:%@",value]];
};
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
*/
#import "RACOperationMethodController.h"
#import <RACReturnSignal.h>
@interface RACOperationMethodController ()
@property (strong, nonatomic) UITextField *textField;
@end
@implementation RACOperationMethodController
- (void)viewDidLoad {
[super viewDidLoad];
[self initView];
[self flattenMap];
[self map];
[self flatternMapWithMap];
[self RACOperationMethodCombination];
}
- (void)initView {
self.navigationItem.title = @"RAC 操作方法一";
self.view.backgroundColor = [UIColor whiteColor];
_textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
_textField.center = self.view.center;
_textField.placeholder = @"請輸入內(nèi)容";
[self.view addSubview:_textField];
}
//flattenMap簡單使用
// 監(jiān)聽文本框的內(nèi)容改變,把結(jié)構(gòu)重新映射成一個(gè)新值.
// flattenMap作用:把源信號的內(nèi)容映射成一個(gè)新的信號绎速,信號可以是任意類型皮获。
- (void)flattenMap {
// flattenMap使用步驟:
// 1.傳入一個(gè)block,block類型是返回值RACStream纹冤,參數(shù)value
// 2.參數(shù)value就是源信號的內(nèi)容洒宝,拿到源信號的內(nèi)容做處理
// 3.包裝成RACReturnSignal信號,返回出去萌京。
// flattenMap底層實(shí)現(xiàn):
// 0.flattenMap內(nèi)部調(diào)用bind方法實(shí)現(xiàn)的,flattenMap中block的返回值雁歌,會(huì)作為bind中bindBlock的返回值。
// 1.當(dāng)訂閱綁定信號知残,就會(huì)生成bindBlock靠瞎。
// 2.當(dāng)源信號發(fā)送內(nèi)容,就會(huì)調(diào)用bindBlock(value, *stop)
// 3.調(diào)用bindBlock求妹,內(nèi)部就會(huì)調(diào)用flattenMap的block乏盐,flattenMap的block作用:就是把處理好的數(shù)據(jù)包裝成信號。
// 4.返回的信號最終會(huì)作為bindBlock中的返回信號制恍,當(dāng)做bindBlock的返回信號父能。
// 5.訂閱bindBlock的返回信號,就會(huì)拿到綁定信號的訂閱者净神,把處理完成的信號內(nèi)容發(fā)送出來何吝。
[[_textField.rac_textSignal flattenMap:^RACStream *(id value) {
// block什么時(shí)候 : 源信號發(fā)出的時(shí)候,就會(huì)調(diào)用這個(gè)block鹃唯。
// block作用 : 改變源信號的內(nèi)容爱榕。
// 返回值:綁定信號的內(nèi)容.
return [RACReturnSignal return:[NSString stringWithFormat:@"輸出:%@",value]];
}] subscribeNext:^(id x) {
// 訂閱綁定信號,每當(dāng)源信號發(fā)送內(nèi)容俯渤,做完處理呆细,就會(huì)調(diào)用這個(gè)block。
NSLog(@"輸出:flattenMap%@",x);
}];
}
- (void)map {
//Map簡單使用:
// 監(jiān)聽文本框的內(nèi)容改變八匠,把結(jié)構(gòu)重新映射成一個(gè)新值.
// Map作用:把源信號的值映射成一個(gè)新的值
// Map使用步驟:
// 1.傳入一個(gè)block,類型是返回對象絮爷,參數(shù)是value
// 2.value就是源信號的內(nèi)容,直接拿到源信號的內(nèi)容做處理
// 3.把處理好的內(nèi)容梨树,直接返回就好了坑夯,不用包裝成信號,返回的值抡四,就是映射的值柜蜈。
// Map底層實(shí)現(xiàn):
// 0.Map底層其實(shí)是調(diào)用flatternMap,Map中block中的返回的值會(huì)作為flatternMap中block中的值仗谆。
// 1.當(dāng)訂閱綁定信號,就會(huì)生成bindBlock淑履。
// 3.當(dāng)源信號發(fā)送內(nèi)容隶垮,就會(huì)調(diào)用bindBlock(value, *stop)
// 4.調(diào)用bindBlock,內(nèi)部就會(huì)調(diào)用flattenMap的block
// 5.flattenMap的block內(nèi)部會(huì)調(diào)用Map中的block秘噪,把Map中的block返回的內(nèi)容包裝成返回的信號狸吞。
// 5.返回的信號最終會(huì)作為bindBlock中的返回信號,當(dāng)做bindBlock的返回信號指煎。
// 6.訂閱bindBlock的返回信號蹋偏,就會(huì)拿到綁定信號的訂閱者,把處理完成的信號內(nèi)容發(fā)送出來至壤。
[[_textField.rac_textSignal map:^id(id value) {
// 當(dāng)源信號發(fā)出威始,就會(huì)調(diào)用這個(gè)block,修改源信號的內(nèi)容
// 返回值:就是處理完源信號的內(nèi)容像街。
return [NSString stringWithFormat:@"輸出:%@",value];
}] subscribeNext:^(id x) {
NSLog(@"map輸出%@",x);
}];
}
- (void)flatternMapWithMap {
/**
FlatternMap和Map的區(qū)別
1.FlatternMap中的Block返回信號黎棠。
2.Map中的Block返回對象。
3.開發(fā)中镰绎,如果信號發(fā)出的值不是信號葫掉,映射一般使用Map
4.開發(fā)中,如果信號發(fā)出的值是信號跟狱,映射一般使用FlatternMap俭厚。
總結(jié):signalOfsignals用FlatternMap。
*/
//創(chuàng)建信號中的信號
RACSubject *signalOfsignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[[signalOfsignals flattenMap:^RACStream *(id value) {
//當(dāng)signalOfsignals的signals發(fā)出信號才會(huì)調(diào)用
return value;
}] subscribeNext:^(id x) {
// 只有signalOfsignals的signal發(fā)出信號才會(huì)調(diào)用驶臊,因?yàn)閮?nèi)部訂閱了bindBlock中返回的信號挪挤,也就是flattenMap返回的信號。
// 也就是flattenMap返回的信號發(fā)出內(nèi)容关翎,才會(huì)調(diào)用扛门。
NSLog(@"%@aaa",x);
}];
// 信號的信號發(fā)送信號
[signalOfsignals sendNext:signal];
// 信號發(fā)送內(nèi)容
[signal sendNext:@1];
}
//RAC 操作之組合
- (void)RACOperationMethodCombination {
//一.concat:按一定順序拼接信號,當(dāng)多個(gè)信號發(fā)出的時(shí)候纵寝,有順序的接收信號论寨。
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
[subscriber sendCompleted];
return nil;
}];
// 把signalA拼接到signalB后,signalA發(fā)送完成爽茴,signalB才會(huì)被激活葬凳。
RACSignal *concatSignal = [signalA concat:signalB];
// 以后只需要面對拼接信號開發(fā)。
// 訂閱拼接的信號室奏,不需要單獨(dú)訂閱signalA火焰,signalB
// 內(nèi)部會(huì)自動(dòng)訂閱。
// 注意:第一個(gè)信號必須發(fā)送完成胧沫,第二個(gè)信號才會(huì)被激活
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// concat底層實(shí)現(xiàn):
// 1.當(dāng)拼接信號被訂閱昌简,就會(huì)調(diào)用拼接信號的didSubscribe
// 2.didSubscribe中占业,會(huì)先訂閱第一個(gè)源信號(signalA)
// 3.會(huì)執(zhí)行第一個(gè)源信號(signalA)的didSubscribe
// 4.第一個(gè)源信號(signalA)didSubscribe中發(fā)送值,就會(huì)調(diào)用第一個(gè)源信號(signalA)訂閱者的nextBlock,通過拼接信號的訂閱者把值發(fā)送出來.
// 5.第一個(gè)源信號(signalA)didSubscribe中發(fā)送完成纯赎,就會(huì)調(diào)用第一個(gè)源信號(signalA)訂閱者的completedBlock,訂閱第二個(gè)源信號(signalB)這時(shí)候才激活(signalB)谦疾。
// 6.訂閱第二個(gè)源信號(signalB),執(zhí)行第二個(gè)源信號(signalB)的didSubscribe
// 7.第二個(gè)源信號(signalA)didSubscribe中發(fā)送值,就會(huì)通過拼接信號的訂閱者把值發(fā)送出來.
//二.then:用于連接兩個(gè)信號,當(dāng)?shù)谝粋€(gè)信號完成犬金,才會(huì)連接then返回的信號餐蔬。
// then:用于連接兩個(gè)信號,當(dāng)?shù)谝粋€(gè)信號完成佑附,才會(huì)連接then返回的信號
// 注意使用then,之前信號的值會(huì)被忽略掉.
// 底層實(shí)現(xiàn):1仗考、先過濾掉之前的信號發(fā)出的值音同。2.使用concat連接then返回的信號
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
}] subscribeNext:^(id x) {
// 只能接收到第二個(gè)信號的值,也就是then返回信號的值
NSLog(@"%@",x);
}];
//三.merge:把多個(gè)信號合并為一個(gè)信號,任何一個(gè)信號有新值的時(shí)候就會(huì)調(diào)用.
//merge: 把多個(gè)信號合并成一個(gè)信號
//創(chuàng)建多個(gè)信號
RACSignal *signalC = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@3];
return [RACDisposable disposableWithBlock:^{
NSLog(@"信號釋放了");
}];
}];
RACSignal *signalD = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@4];
return [RACDisposable disposableWithBlock:^{
NSLog(@"信號釋放了");
}];
}];
//合并信號.任何一個(gè)信號發(fā)送數(shù)據(jù),都能監(jiān)聽到
RACSignal *mergeSignal = [signalC merge:signalD];
[mergeSignal subscribeNext:^(id x) {
NSLog(@"合并信號,任何一個(gè)數(shù)據(jù)發(fā)送數(shù)據(jù),都能監(jiān)聽到%@",x);
}];
// 底層實(shí)現(xiàn):
// 1.合并信號被訂閱的時(shí)候秃嗜,就會(huì)遍歷所有信號权均,并且發(fā)出這些信號。
// 2.每發(fā)出一個(gè)信號锅锨,這個(gè)信號就會(huì)被訂閱
// 3.也就是合并信號一被訂閱叽赊,就會(huì)訂閱里面所有的信號。
// 4.只要有一個(gè)信號被發(fā)出就會(huì)被監(jiān)聽必搞。
//四.zipWith:把兩個(gè)信號壓縮成一個(gè)信號必指,只有當(dāng)兩個(gè)信號同時(shí)發(fā)出信號內(nèi)容時(shí),并且把兩個(gè)信號的內(nèi)容合并成一個(gè)元組恕洲,才會(huì)觸發(fā)壓縮流的next事件塔橡。
RACSignal *signalE = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *signalF = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@6];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 壓縮信號A,信號B
RACSignal *zipSignal = [signalE zipWith:signalF];
[zipSignal subscribeNext:^(id x) {
NSLog(@"壓縮的信號%@",x);
}];
// 底層實(shí)現(xiàn):
// 1.定義壓縮信號霜第,內(nèi)部就會(huì)自動(dòng)訂閱signalA葛家,signalB
// 2.每當(dāng)signalA或者signalB發(fā)出信號,就會(huì)判斷signalA泌类,signalB有沒有發(fā)出個(gè)信號癞谒,有就會(huì)把最近發(fā)出的信號都包裝成元組發(fā)出。
//第五:combineLatest:將多個(gè)信號合并起來刃榨,并且拿到各個(gè)信號的最新的值,必須每個(gè)合并的signal至少都有過一次sendNext弹砚,才會(huì)觸發(fā)合并的信號.
RACSignal *signalG = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *signalH = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@6];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 把兩個(gè)信號組合成一個(gè)信號,跟zip一樣,沒什么區(qū)別
RACSignal *combineSignal = [signalG combineLatestWith:signalH];
[combineSignal subscribeNext:^(id x) {
NSLog(@"把兩個(gè)信號組合成一個(gè)信號%@",x);
}];
// 底層實(shí)現(xiàn):
// 1.當(dāng)組合信號被訂閱枢希,內(nèi)部會(huì)自動(dòng)訂閱signalA迅栅,signalB,必須兩個(gè)信號都發(fā)出內(nèi)容,才會(huì)被觸發(fā)晴玖。
// 2.并且把兩個(gè)信號組合成元組發(fā)出读存。
//第六:reduce聚合:用于信號發(fā)出的內(nèi)容是元組为流,把信號發(fā)出元組的值聚合成一個(gè)值
RACSignal *signalL = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *signalM = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@6];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *reduceSignal = [RACSignal combineLatest:@[signalL,signalM] reduce:^id(NSNumber *num1, NSNumber *num2){
return [NSString stringWithFormat:@"reduce聚合%@ %@",num1,num2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// // 底層實(shí)現(xiàn):
// 1.訂閱聚合信號,每次有內(nèi)容發(fā)出让簿,就會(huì)執(zhí)行reduceblcok敬察,把信號內(nèi)容轉(zhuǎn)換成reduceblcok返回的值。
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
8.RAC操作方法二
#import <UIKit/UIKit.h>
@interface RACOperationMethodFilteringVC : UIViewController
@end
#import "RACOperationMethodFilteringVC.h"
@interface RACOperationMethodFilteringVC ()
@property (strong, nonatomic) UITextField *textField;
@end
@implementation RACOperationMethodFilteringVC
- (void)viewDidLoad {
[super viewDidLoad];
[self initView];
[self filter];
[self ignore];
[self ignoreValues];
[self takeUntilBlock];
[self distinctUntilChanged];
[self take];
[self takeLast];
[self takeUntil];
[self skip];
[self switchToLatest];
}
- (void)initView {
self.navigationItem.title = @"RAC操作方法二";
self.view.backgroundColor = [UIColor whiteColor];
_textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
_textField.center = self.view.center;
_textField.borderStyle = UITextBorderStyleBezel;
_textField.placeholder = @"請輸入內(nèi)容";
[self.view addSubview:_textField];
}
//過濾信號尔当,使用它可以獲取滿足條件的信號.
- (void)filter {
//filter 過濾
//每次信號發(fā)出,會(huì)先執(zhí)行過濾條件判斷
[_textField.rac_textSignal filter:^BOOL(NSString *value) {
return value.length > 3;
}];
}
//ignore:忽略完某些值的信號.
- (void)ignore {
// 內(nèi)部調(diào)用filter過濾莲祸,忽略掉ignore的值
[[_textField.rac_textSignal ignore:@"1"] subscribeNext:^(id x) {
NSLog(@"ignore%@",x);
}];
}
//ignoreValues 這個(gè)比較極端,忽略所有值椭迎,只關(guān)心Signal結(jié)束锐帜,也就是只取Comletion和Error兩個(gè)消息,中間所有值都丟棄
- (void)ignoreValues {
RACSignal *signal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"3"];
[subscriber sendNext:@"15"];
[subscriber sendNext:@"wujy"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"執(zhí)行清理");
}];
}];
[[signal ignoreValues] subscribeNext:^(id x) {
//它是沒機(jī)會(huì)執(zhí)行 因?yàn)閕gnoreValues已經(jīng)忽略所有的next值
NSLog(@"ignoreValues當(dāng)前值:%@",x);
} error:^(NSError *error) {
NSLog(@"ignoreValues error");
} completed:^{
NSLog(@"ignoreValues completed");
}];
}
//distinctUntilChanged:當(dāng)上一次的值和當(dāng)前的值有明顯的變化就會(huì)發(fā)出信號畜号,否則會(huì)被忽略掉缴阎。
- (void)distinctUntilChanged {
// 過濾,當(dāng)上一次和當(dāng)前的值不一樣简软,就會(huì)發(fā)出內(nèi)容蛮拔。
// 在開發(fā)中,刷新UI經(jīng)常使用痹升,只有兩次數(shù)據(jù)不一樣才需要刷新
[[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"distinctUntilChanged%@",x);
}];
}
//take:從開始一共取N次的信號
- (void)take {
//1.創(chuàng)建信號
RACSubject *signal = [RACSubject subject];
//2.處理信號,訂閱信號
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"take:%@",x);
}];
// 3.發(fā)送信號
[signal sendNext:@1];
[signal sendNext:@2];
}
//takeLast:取最后N次的信號,前提條件建炫,訂閱者必須調(diào)用完成,因?yàn)橹挥型瓿商鄱辏椭揽偣灿卸嗌傩盘?
- (void)takeLast {
//1.創(chuàng)建信號
RACSubject *signal = [RACSubject subject];
//2.處理信號,訂閱信號
[[signal takeLast:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//3.發(fā)送信號
[signal sendNext:@1];
[signal sendNext:@332];
[signal sendNext:@333];
[signal sendCompleted];
}
//takeUntil:(RACSignal *):獲取信號直到執(zhí)行完這個(gè)信號
- (void)takeUntil {
// 監(jiān)聽文本框的改變肛跌,知道當(dāng)前對象被銷毀
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
}
//takeUntilBlock 對于每個(gè)next值,運(yùn)行block察郁,當(dāng)block返回YES時(shí)停止取值
- (void)takeUntilBlock {
RACSignal *signal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"3"];
[subscriber sendNext:@"15"];
[subscriber sendNext:@"wujy"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"執(zhí)行清理");
}];
}];
[[signal takeUntilBlock:^BOOL(NSString *x) {
if ([x isEqualToString:@"15"]) {
return YES;
}
return NO;
}] subscribeNext:^(id x) {
NSLog(@"takeUntilBlock 獲取的值:%@",x);
}];
// 輸出
// takeUntilBlock 獲取的值:1
// takeUntilBlock 獲取的值:3
}
//skip:(NSUInteger):跳過幾個(gè)信號,不接受惋砂。
- (void)skip {
[[_textField.rac_textSignal skip:1] subscribeNext:^(id x) {
NSLog(@"跳過幾個(gè)信號不接收%@",x);
}];
}
//switchToLatest:用于signalOfSignals(信號的信號),有時(shí)候信號也會(huì)發(fā)出信號绳锅,會(huì)在signalOfSignals中西饵,獲取signalOfSignals發(fā)送的最新信號。
- (void)switchToLatest {
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[signalOfSignals sendNext:signal];
// 獲取信號中信號最近發(fā)出信號鳞芙,訂閱最近發(fā)出的信號眷柔。
// 注意switchToLatest:只能用于信號中的信號
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"獲取信號中信號最近發(fā)出信號,訂閱最近發(fā)出的信號%@",x);
}];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
9.RAC操作方法三
#import <UIKit/UIKit.h>
@interface RACOperationOrderController : UIViewController
@end
#import "RACOperationOrderController.h"
@interface RACOperationOrderController ()
@property (nonatomic, strong) RACSubject *signal;
@end
@implementation RACOperationOrderController
- (void)viewDidLoad {
[super viewDidLoad];
[self initView];
[self doNext];
[self deliverOn];
[self timeout];
[self interval];
[self delay];
[self retry];
[self replay];
[self throttle];
}
- (void)initView {
self.navigationItem.title = @"RAC操作方法三";
self.view.backgroundColor = [UIColor whiteColor];
}
//ReactiveCocoa操作方法之秩序原朝。
- (void)doNext {
//doNext: 執(zhí)行Next之前驯嘱,會(huì)先執(zhí)行這個(gè)Block
//doCompleted: 執(zhí)行sendCompleted之前,會(huì)先執(zhí)行這個(gè)Block
[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] doNext:^(id x) {
// 執(zhí)行[subscriber sendNext:@1];之前會(huì)調(diào)用這個(gè)Block
NSLog(@"doNext");
}] doCompleted:^{
// 執(zhí)行[subscriber sendCompleted];之前會(huì)調(diào)用這個(gè)Block
NSLog(@"doCompleted");
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
//ReactiveCocoa操作方法之線程喳坠。
- (void)deliverOn {
//deliverOn: 內(nèi)容傳遞切換到制定線程中鞠评,副作用在原來線程中,把在創(chuàng)建信號時(shí)block中的代碼稱之為副作用。
//subscribeOn: 內(nèi)容傳遞和副作用都會(huì)切換到制定線程中。
}
//ReactiveCocoa操作方法之時(shí)間瘦馍。
- (void)timeout {
//timeout:超時(shí)衅枫,可以讓一個(gè)信號在一定的時(shí)間后策精,自動(dòng)報(bào)錯(cuò)。
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
return nil;
}] timeout:1 onScheduler:[RACScheduler currentScheduler]];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
// 1秒后會(huì)自動(dòng)調(diào)用
NSLog(@"%@",error);
}];
}
//interval 定時(shí):每隔一段時(shí)間發(fā)出信號
- (void)interval {
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
}
//delay 延遲發(fā)送next
- (void)delay {
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
// ReactiveCocoa操作方法之重復(fù)政己。
- (void)retry {
//retry重試 :只要失敗首有,就會(huì)重新執(zhí)行創(chuàng)建信號中的block,直到成功.
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (i == 10) {
[subscriber sendNext:@1];
}else{
NSLog(@"接收到錯(cuò)誤");
[subscriber sendError:nil];
}
i++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
}];
}
//replay重放:當(dāng)一個(gè)信號被多次訂閱,反復(fù)播放內(nèi)容
- (void)replay {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一個(gè)訂閱者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二個(gè)訂閱者%@",x);
}];
}
- (void)throttle {
RACSubject *signal = [RACSubject subject];
_signal = signal;
// 節(jié)流锻梳,在一定時(shí)間(1秒)內(nèi)抖棘,不接收任何信號內(nèi)容茂腥,過了這個(gè)時(shí)間(1秒)獲取最后發(fā)送的信號內(nèi)容發(fā)出。
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end