RAC系统化学习
1、RACSignal:
// 只要订阅者调用sendNext,就会执行nextBlock
// 只要订阅RACDynamicSignal,就会执行didSubscribe
// 前提条件是RACDynamicSignal,不同类型信号的订阅,处理订阅的事情不一样
//创建信号,此时信号是冷信号,并不能发送数据 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"发送数据"];
//信号销毁 return [RACDisposable disposableWithBlock:^{ NSLog(@"信号取消订阅"); }]; }]; //信号订阅,此时信号变为热信号,接收到数据 [signal subscribeNext:^(id x) {
// nextBlock调用:只要订阅者发送数据就会调用
NSLog(@"%@", x); }];
2、RACSubject
//创建信号 RACSubject *subject = [RACSubject subject]; /* 不同信号订阅的方式不一样 RACSubject处理订阅:仅仅是保存订阅者,可以多个订阅者 底层实现:遍历所有的订阅者,调用nextBlock 执行流程: RACSubject被订阅,仅仅是保存订阅者 RACSubject发送数据,遍历所有的订阅,调用他们的nextBlock */ [subject subscribeNext:^(id x) { NSLog(@"++++++%@", x); }]; [subject subscribeNext:^(id x) { NSLog(@"-----%@", x); }]; [subject sendNext:@111];
3、RACReplaySubject
//创建信号 RACReplaySubject *replaySubject = [RACReplaySubject subject]; //可以先发送数据再订阅信号 [replaySubject sendNext:@111111]; [replaySubject subscribeNext:^(id x) { NSLog(@"---%@", x); }]; [replaySubject subscribeNext:^(id x) { NSLog(@"+++++%@", x); }];
4、RAC中的KVO、通知、监听事件、监听文本框、计时器
//KVO
//方式一:其中_redView是属性UIView,监听frame变化 [_redView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { //value就是frame变化之后的值 NSLog(@"----%@", value); }];
//方式二: [[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) { NSLog(@"+++++%@", x); }]; //监听事件,监听按钮的点击事件 [[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { NSLog(@"控制器按钮被点击"); }];
//_label增加点击手势,监听点击事件 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init]; [[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer *x) { NSLog(@"----label增加单击手势%@", x); }]; [_label addGestureRecognizer:tap]; //通知,监听键盘弹起的通知 [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) { NSLog(@"%@", x); }]; //监听文本框,只要文本框中内容一产生变化,就会走这个block [_textField.rac_textSignal subscribeNext:^(id x) { NSLog(@"%@", x); }]; [[_textField rac_signalForControlEvents:UIControlEventEditingDidEndOnExit] subscribeNext:^(id x) { //return之后隐藏键盘 //x是TextField NSLog(@"%@",x); }]; //延迟一定时间做某事 [[RACScheduler mainThreadScheduler]afterDelay:2.0f schedule:^{ NSLog(@"2秒之后发生的事情"); }]; // 每个一定长度时间做一件事,类似NSTimer [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; _label.text = [formatter stringFromDate:date]; // NSLog(@"%@",[formatter stringFromDate:date]); }];
//监听UIAlertView弹框的点击事件 UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"警告" message:@"是否确认登录?" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
//实现alertView的点击事件的delegate方法 [[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) { //点击取消、确定按钮会到本block RACTupleUnpack(UIAlertView *alert, NSNumber *index) = tuple; NSLog(@"alertView : %@------%@",alert, index); }]; [alertView show]; //类似UIAlertView UIActionSheet *sheet = [[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"相机", @"相册", nil]; [[self rac_signalForSelector:@selector(actionSheet:clickedButtonAtIndex:) fromProtocol:@protocol(UIActionSheetDelegate)] subscribeNext:^(RACTuple * tuple) { RACTupleUnpack(UIActionSheet *alert, NSNumber *index) = tuple; NSLog(@"alertView : %@------%@",alert, index); }]; [sheet showInView:self.view];
5、RAC中的集合:
//类似NSArray
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@1, @"dssds", @3]]; NSNumber *first = tuple[0]; NSLog(@"%@", first); //array NSArray *array = @[@"123", @"456", @"789"]; //RAC集合 RACSequence *sequence = array.rac_sequence; //转化为信号 RACSignal *signal = sequence.signal; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }];
//联合起来遍历数据就是: [array.rac_sequence.signal subscribeNext:^(id x) { NSLog(@"------%@", x); }]; //Dict NSDictionary *dict = @{@"name" : @"小明", @"age" : @"20"}; [dict.rac_sequence.signal subscribeNext:^(RACTuple *x) { // NSString *key = x[0]; // NSString *value = x[1]; // NSLog(@"key : %@, value : %@", key, value); // RACTupleUnpack:用来解析元组 // 宏里面的参数,传需要解析出来的变量名 // = 右边,放需要解析的元组 RACTupleUnpack(NSString *key, NSString *value) = x; NSLog(@"%@--%@", key, value); }]; NSArray *allModels = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil]]; // NSMutableArray *models = [NSMutableArray array]; // [allModels.rac_sequence.signal subscribeNext:^(NSDictionary *x) { // // FlagModel *model = [FlagModel flagWithDict:x]; // [models addObject:model]; // // }];
//models数组中的数据是已经将数据转好的模型数据 NSArray *models = [[allModels.rac_sequence map:^id(id value) {
//字典转模型 return [FlagModel flagWithDict:value]; }] array]; NSLog(@"-----%@", models);
6、RACMulticastConnection
//弊端:有几个订阅者就会请求几次数据 // 1.创建信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@"发送热门模块的请求"); // 3.发送数据 [subscriber sendNext:@1]; return nil; }]; // 2.订阅信号 [signal subscribeNext:^(id x) { NSLog(@"订阅者一%@",x); }]; [signal subscribeNext:^(id x) { NSLog(@"订阅者二%@",x); }]; //弊端优化 // 不管订阅多少次信号,就会请求一次 // RACMulticastConnection:必须要有信号 // 1.创建信号 RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // didSubscribe什么时候来:连接类连接的时候 NSLog(@"发送热门模块的请求"); [subscriber sendNext:@"热门模块的数据"]; return nil; }]; // 2.把信号转换成连接类 // 确定源信号的订阅者RACSubject // RACMulticastConnection *connection = [signal publish]; RACMulticastConnection *connection = [signal2 multicast:[RACReplaySubject subject]]; // 3.订阅连接类信号 [connection.signal subscribeNext:^(id x) { // nextBlock:发送数据就会来 NSLog(@"订阅者1:%@",x); }]; // 4.连接 [connection connect];
7、RACCommand
//创建RACCommand,RACCommand命令在RAC很常用,常用语网络请求
RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal *(id input) { NSLog(@"---input = %@", input); //11 return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//网络请求,将请求的数据发送出去 [subscriber sendNext:@"网络请求的数据"]; return nil; }]; }]; //取到command创建的RACSignal //方式一: RACSignal *signal = [command execute:@1]; [signal subscribeNext:^(id x) { NSLog(@"---%@", x); }]; //方式2: // 注意:必须要在执行命令前,订阅 // executionSignals:信号源,信号中信号,signalOfSignals:信号:发送数据就是信号 [command.executionSignals subscribeNext:^(RACSignal *x) { NSLog(@"%@", x); [x subscribeNext:^(id x) { NSLog(@"%@", x); }]; }]; //方式3: switchToLatest获取最新发送的信号,只能用于信号中信号 [command.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"--x = %@", x); }]; [command execute:@23]; //下面对信号中的信号讲解: // 创建信号中信号 RACSubject *signalOfSignals = [RACSubject subject]; RACSubject *signalA = [RACSubject subject]; RACSubject *signalB = [RACSubject subject]; // 订阅信号 // [signalOfSignals subscribeNext:^(RACSignal *x) { // [x subscribeNext:^(id x) { // NSLog(@"%@",x); // }]; // }]; // switchToLatest:获取信号中信号发送的最新信号 [signalOfSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"%@",x); }]; // 发送信号 [signalOfSignals sendNext:signalA]; [signalA sendNext:@1]; [signalB sendNext:@"BB"]; [signalA sendNext:@"11"]; //********************************************************************************************************************** // 当前命令内部发送数据完成,一定要主动发送完成 // 1.创建命令 RACCommand *command2 = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { // input:执行命令传入参数 // Block调用:执行命令的时候就会调用 NSLog(@"%@",input); return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送数据 [subscriber sendNext:@"执行命令产生的数据"]; // 发送完成 [subscriber sendCompleted]; return nil; }]; }]; // 监听事件有没有完成 [command2.executing subscribeNext:^(id x) { if ([x boolValue] == YES) { // 当前正在执行 NSLog(@"当前正在执行"); }else{ // 执行完成/没有执行 NSLog(@"执行完成/没有执行"); } }]; // 2.执行命令 [command2 execute:@1];
8、bind,信号的绑定
// 1.创建信号 RACSubject *subject = [RACSubject subject]; // 2.绑定信号 RACSignal *bindSignal = [subject bind:^RACStreamBindBlock{ // block调用时刻:只要绑定信号被订阅就会调用 return ^RACSignal *(id value, BOOL *stop){ // block调用:只要源信号发送数据,就会调用block // block作用:处理源信号内容 // value:源信号发送的内容 NSLog(@"接收到原信号的内容:%@",value); value = [NSString stringWithFormat:@"xmg:%@",value]; // 返回信号,不能传nil,返回空信号[RACSignal empty] return [RACReturnSignal return:value]; }; }]; // 3.订阅绑定信号 [bindSignal subscribeNext:^(id x) { // blcok:当处理完信号发送数据的时候,就会调用这个Block NSLog(@"接收到绑定信号处理完的信号%@",x); }]; // 4.发送数据 [subject sendNext:@"123"];
9、map、flattenMap
//map、flattenMap主要是对发送的数据进行编辑,如:可以将网络请求的数据转化的模型在发送
// 创建信号, RACSubject *subject2 = [RACSubject subject]; // 绑定信号 RACSignal *bindSignal2 = [subject2 map:^id(id value) { // 返回的类型,就是你需要映射的值 return [NSString stringWithFormat:@"请求的数据:%@",value]; }]; // 订阅绑定信号 [bindSignal2 subscribeNext:^(id x) { NSLog(@"%@",x); }]; [subject2 sendNext:@"123"]; //******************flattenMap一般用于信号中的信号******************************* RACSubject *signalOfsignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; [[signalOfsignals flattenMap:^RACStream *(id value) { return value; }] subscribeNext:^(id x) { NSLog(@"%@",x); }]; // 发送信号 [signalOfsignals sendNext:signal]; [signal sendNext:@"213"];
10、组合
// 组合,两个信号都完成才执行 // concat:皇上,皇太子 // 创建信号A RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 NSLog(@"发送上部分请求"); // 发送信号 [subscriber sendNext:@"上部分数据"]; [subscriber sendCompleted]; return nil; }]; RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 NSLog(@"发送下部分请求"); // 发送信号 [subscriber sendNext:@"下部分数据"]; return nil; }]; // concat:按顺序去连接 // 注意:concat,第一个信号必须要调用sendCompleted // 创建组合信号 RACSignal *concatSignal = [siganlA concat:siganlB]; // 订阅组合信号 [concatSignal subscribeNext:^(id x) { // 既能拿到A信号的值,又能拿到B信号的值 NSLog(@"%@",x); }]; //*************************************************************************************************** // 创建信号A RACSignal *siganl1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 NSLog(@"发送上部分请求"); // 发送信号 [subscriber sendNext:@"上部分数据"]; // 发送完成 [subscriber sendCompleted]; return nil; }]; // 创建信号B RACSignal *siganl2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 NSLog(@"发送下部分请求"); // 发送信号 [subscriber sendNext:@"下部分数据"]; return nil; }]; // 创建组合信号 // then:忽悠掉第一个信号所有值 RACSignal *thenSiganl = [siganl1 then:^RACSignal *{ // 返回信号就是需要组合的信号 return siganl2; }]; // 订阅信号 [thenSiganl subscribeNext:^(id x) { NSLog(@"%@",x); }]; //*************************************************************************************************** // 创建信号A RACSubject *signalA = [RACSubject subject]; // 创建信号B RACSubject *signalB = [RACSubject subject]; // 组合信号 RACSignal *mergeSiganl = [signalA merge:signalB]; // 订阅信号 [mergeSiganl subscribeNext:^(id x) { // 任意一个信号发送内容都会来这个block NSLog(@"%@",x); }]; // 发送数据 [signalB sendNext:@"下部分"]; [signalA sendNext:@"上部分"]; //*************************************************************************************************** // zipWith:夫妻关系 // 创建信号A RACSubject *signalC = [RACSubject subject]; // 创建信号B RACSubject *signalD = [RACSubject subject]; // 压缩成一个信号 // zipWith:当一个界面多个请求的时候,要等所有请求完成才能更新UI // zipWith:等所有信号都发送内容的时候才会调用 RACSignal *zipSignal = [signalC zipWith:signalD]; // 订阅信号 [zipSignal subscribeNext:^(id x) { NSLog(@"%@",x); }]; // 发送信号 [signalD sendNext:@2]; [signalC sendNext:@1]; //*************************************************************************************************** // 组合 // 组合哪些信号 // reduce:聚合 // reduceBlock参数:根组合的信号有关,一一对应 RACSignal *comineSiganl = [RACSignal combineLatest:@[_accountFiled.rac_textSignal,_pwdField.rac_textSignal] reduce:^id(NSString *account,NSString *pwd){ // block:只要源信号发送内容就会调用,组合成新一个值 NSLog(@"%@ %@",account,pwd); // 聚合的值就是组合信号的内容 return @(account.length && pwd.length); }]; // 订阅组合信号 // [comineSiganl subscribeNext:^(id x) { // _loginBtn.enabled = [x boolValue]; // }]; RAC(_loginBtn,enabled) = comineSiganl;
11、过滤
// 只有当我们文本框的内容长度大于5,才想要获取文本框的内容 [[_textField.rac_textSignal filter:^BOOL(id value) { // value:源信号的内容 return [value length] > 5; // 返回值,就是过滤条件,只有满足这个条件,才能能获取到内容 }] subscribeNext:^(id x) { NSLog(@"%@",x); }]; //*************************************************************************************************** // ignore:忽略一些值 // ignoreValues:忽略所有的值 // 1.创建信号 RACSubject *subject = [RACSubject subject]; // 2.忽略一些 RACSignal *ignoreSignal = [subject ignoreValues]; // 3.订阅信号 [ignoreSignal subscribeNext:^(id x) { NSLog(@"%@",x); }]; // 4.发送数据 [subject sendNext:@"13"]; [subject sendNext:@"2"]; [subject sendNext:@"44"]; //*************************************************************************************************** // 1.创建信号 RACSubject *subject2 = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; // take:取前面几个值 // takeLast:取后面多少个值.必须要发送完成 // takeUntil:只要传入信号发送完成或者发送任意数据,就不能在接收源信号的内容 [[subject2 takeUntil:signal] subscribeNext:^(id x) { NSLog(@"%@",x); }]; [subject2 sendNext:@"1"]; // [signal sendNext:@1]; // [signal sendCompleted]; [signal sendError:nil]; [subject2 sendNext:@"2"]; [subject2 sendNext:@"3"]; //*************************************************************************************************** // distinctUntilChanged:如果当前的值跟上一个值相同,就不会被订阅到 // 1.创建信号 RACSubject *subject3 = [RACSubject subject]; [[subject3 distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"%@",x); }]; [subject3 sendNext:@"1"]; [subject3 sendNext:@"2"]; [subject3 sendNext:@"2"]; //*************************************************************************************************** // skip;跳跃几个值 // 1.创建信号 RACSubject *subject4 = [RACSubject subject]; [[subject4 skip:2] subscribeNext:^(id x) { NSLog(@"%@",x); }]; [subject4 sendNext:@"1"]; [subject4 sendNext:@"2"]; [subject4 sendNext:@"3"];
12、RAC其他一些操作
//******************************************** [[[[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] doNext:^(id x) { [self.btn setTitle:@"你好" forState:UIControlStateNormal]; }] map:^id(id value) { return @(YES); }] subscribeNext:^(NSNumber *x) { self.btn.backgroundColor = x ? [UIColor orangeColor] : [UIColor cyanColor]; }]; //************************************************************** //doNext: 执行Next之前,会先执行这个Block //doCompleted: 执行sendCompleted之前,会先执行这个Block [[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }] doNext:^(id x) { // 执行[subscriber sendNext:@1];之前会调用这个Block NSLog(@"doNext");; }] doCompleted:^{ // 执行[subscriber sendCompleted];之前会调用这个Block NSLog(@"doCompleted");; }] subscribeNext:^(id x) { NSLog(@"%@",x); }]; //********************************************************* //timeout:超时,可以让一个信号在一定的时间后,自动报错。 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秒后会自动调用 NSLog(@"%@",error); }]; //interval 定时:每隔一段时间发出信号 [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) { NSLog(@"%@",x); }]; //delay 延迟发送next。 [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; return nil; }] delay:2] subscribeNext:^(id x) { NSLog(@"%@",x); }]; //********************************************************* //retry重试 :只要失败,就会重新执行创建信号中的block,直到成功. __block int i = 0; [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { if (i == 10) { [subscriber sendNext:@1]; }else{ NSLog(@"接收到错误"); [subscriber sendError:nil]; } i++; return nil; }] retry] subscribeNext:^(id x) { NSLog(@"%@",x); } error:^(NSError *error) { }]; //********************************************************* //replay重放:当一个信号被多次订阅,反复播放内容 RACSignal *signal3 = [[RACSignal createSignal:^RACDisposable* (id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; return nil; }] replay]; [signal3 subscribeNext:^(id x) { NSLog(@"第一个订阅者%@",x); }]; [signal3 subscribeNext:^(id x) { NSLog(@"第二个订阅者%@",x); }]; //********************************************************* //throttle节流:当某个信号发送比较频繁时,可以使用节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出。 RACSubject *signal4 = [RACSubject subject]; // _signal = signal; // 节流,在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出。 [[signal4 throttle:1] subscribeNext:^(id x) { NSLog(@"%@",x); }];
13、RAC中常用的宏:
//1、防止循环引用,类似__weak typeof(self)waekSelf = self; @weakify(self) [_textField.rac_textSignal subscribeNext:^(NSString *x) { @strongify(self) self.textField.text = x; }]; //2、包装元组 RACTuple *tuple = RACTuplePack(@1, @2); NSLog(@"---%@", tuple[0]); //之前赋值方式 // [_textField.rac_textSignal subscribeNext:^(id x) { // // _label.text = x; // // }]; // 用来给某个对象的某个属性绑定信号,只要产生信号内容,就会把内容给属性赋值 RAC(_label, text) = _textField.rac_textSignal;
如需转载,请注明出处