ReactiveCocoa常用方法总结
1、RACSignal使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // RACSignal使用步骤: // 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe // 2.订阅信号,才会激活信号. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock // 3.发送信号 - (void)sendNext:(id)value // RACSignal底层实现: // 1.创建信号,首先把didSubscribe保存到信号中,还不会触发。 // 2.当信号被订阅,也就是调用signal的subscribeNext:nextBlock // 2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中。 // 2.1 subscribeNext内部会调用siganl的didSubscribe // 3.siganl的didSubscribe中调用[subscriber sendNext:@1]; // 3.1 sendNext底层其实就是执行subscriber的nextBlock // 1.创建信号 RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // block调用时刻:每当有订阅者订阅信号,就会调用block。 // 2.发送信号 [subscriber sendNext:@ 1 ]; // 如果不在发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号。 [subscriber sendCompleted]; return [RACDisposable disposableWithBlock:^{ // block调用时刻:当信号发送完成或者发送错误,就会自动执行这个block,取消订阅信号。 // 执行完Block后,当前信号就不在被订阅了。 NSLog(@ "信号被销毁" ); }]; }]; // 3.订阅信号,才会激活信号. [siganl subscribeNext:^(id x) { // block调用时刻:每当有信号发出数据,就会调用block. NSLog(@ "接收到数据:%@" ,x); }]; |
2、RACSubject当做代理使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 步骤一:在第二个控制器.h,添加一个RACSubject代替代理。 @ interface TwoViewController : UIViewController @property (nonatomic, strong) RACSubject *delegateSignal; @end 步骤二:监听第二个控制器按钮点击 @implementation TwoViewController - (IBAction)notice:(id)sender { // 通知第一个控制器,告诉它,按钮被点了 // 通知代理 // 判断代理信号是否有值 if (self.delegateSignal) { // 有值,才需要通知 [self.delegateSignal sendNext:nil]; } } @end 步骤三:在第一个控制器中,监听跳转按钮,给第二个控制器的代理信号赋值,并且监听. @implementation OneViewController - (IBAction)btnClick:(id)sender { // 创建第二个控制器 TwoViewController *twoVc = [[TwoViewController alloc] init]; // 设置代理信号 twoVc.delegateSignal = [RACSubject subject]; // 订阅代理信号 [twoVc.delegateSignal subscribeNext:^(id x) { NSLog(@ "点击了通知按钮" ); }]; // 跳转到第二个控制器 [self presentViewController:twoVc animated:YES completion:nil]; } @end |
3、RACSequence和RACTuple结合使用遍历字典和数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | // 1.遍历数组 NSArray *numbers = @[@ 1 ,@ 2 ,@ 3 ,@ 4 ]; // 这里其实是三步 // 第一步: 把数组转换成集合RACSequence numbers.rac_sequence // 第二步: 把集合RACSequence转换RACSignal信号类,numbers.rac_sequence.signal // 第三步: 订阅信号,激活信号,会自动把集合中的所有值,遍历出来。 [numbers.rac_sequence.signal subscribeNext:^(id x) { NSLog(@ "%@" ,x); }]; // 2.遍历字典,遍历出来的键值对会包装成RACTuple(元组对象) NSDictionary *dict = @{@ "name" :@ "xmg" ,@ "age" :@ 18 }; [dict.rac_sequence.signal subscribeNext:^(RACTuple *x) { // 解包元组,会把元组的值,按顺序给参数里面的变量赋值 RACTupleUnpack(NSString *key,NSString *value) = x; // 相当于以下写法 // NSString *key = x[0]; // NSString *value = x[1]; NSLog(@ "%@ %@" ,key,value); }]; // 3.字典转模型 // 3.1 OC写法 NSString *filePath = [[NSBundle mainBundle] pathForResource:@ "test.plist" ofType:nil]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath]; NSMutableArray *items = [NSMutableArray array]; for (NSDictionary *dict in dictArr) { TestModel *item = [TestModel yy_modelWithDictionary:dict]; [items addObject:item]; } // 3.2 RAC写法 NSString *filePath = [[NSBundle mainBundle] pathForResource:@ "test.plist" ofType:nil]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath]; NSMutableArray *flags = [NSMutableArray array]; // rac_sequence注意点:调用subscribeNext,并不会马上执行nextBlock,而是会等一会。 [dictArr.rac_sequence.signal subscribeNext:^(id x) { // 运用RAC遍历字典,x:字典 TestModel *item = [TestModel yy_modelWithDictionary:dict]; [flags addObject:item]; }]; // 3.3 RAC高级写法: NSString *filePath = [[NSBundle mainBundle] pathForResource:@ "test.plist" ofType:nil]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath]; // map:映射的意思,目的:把原始值value映射成一个新值 // array: 把集合转换成数组 // 底层实现:当信号被订阅,会遍历集合中的原始值,映射成新值,并且保存到新的数组里。 NSArray *flags = [[dictArr.rac_sequence map:^id(id value) { return [TestModel yy_modelWithDictionary: value]; }] array]; |
4、RACCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | // 一、RACCommand使用步骤: // 1.创建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock // 2.在signalBlock中,创建RACSignal,并且作为signalBlock的返回值 // 3.执行命令 - (RACSignal *)execute:(id)input // 二、RACCommand使用注意: // 1.signalBlock必须要返回一个信号,不能传nil. // 2.如果不想要传递信号,直接创建空的信号[RACSignal empty]; // 3.RACCommand中信号如果数据传递完,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中。 // 4.RACCommand需要被强引用,否则接收不到RACCommand中的信号,因此RACCommand中的信号是延迟发送的。 // 三、RACCommand设计思想:内部signalBlock为什么要返回一个信号,这个信号有什么用。 // 1.在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。 // 2.当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了。 // 四、如何拿到RACCommand中返回信号发出的数据。 // 1.RACCommand有个执行信号源executionSignals,这个是signal of signals(信号的信号),意思是信号发出的数据是信号,不是普通的类型。 // 2.订阅executionSignals就能拿到RACCommand中返回的信号,然后订阅signalBlock返回的信号,就能获取发出的值。 // 五、监听当前命令是否正在执行executing // 六、使用场景,监听按钮点击,网络请求 // 1.创建命令 RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@ "执行命令" ); // 创建空信号,必须返回信号 // return [RACSignal empty]; // 2.创建信号,用来传递数据 return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@ "请求数据" ]; // 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。 [subscriber sendCompleted]; return nil; }]; }]; // 强引用命令,不要被销毁,否则接收不到数据 _conmmand = command; // 3.订阅RACCommand中的信号 [command.executionSignals subscribeNext:^(id x) { [x subscribeNext:^(id x) { NSLog(@ "%@" ,x); }]; }]; // RAC高级用法 // switchToLatest:用于signal of signals,获取signal of signals发出的最新信号,也就是可以直接拿到RACCommand中的信号 [command.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@ "%@" ,x); }]; // 4.监听命令是否执行完毕,默认会来一次,可以直接跳过,skip表示跳过第一次信号。 [[command.executing skip: 1 ] subscribeNext:^(id x) { if ([x boolValue] == YES) { // 正在执行 NSLog(@ "正在执行" ); } else { // 执行完成 NSLog(@ "执行完成" ); } }]; // 5.执行命令 [self.conmmand execute:@ 1 ]; |
5、其余常见用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 1 代替代理: //rac_signalForSelector:用于替代代理。(没有想明白) 2 代替KVO : rac_valuesAndChangesForKeyPath:用于监听某个对象的属性改变。 // 把监听redV的center属性改变转换成信号,只要值改变就会发送信号 // observer:可以传入nil [[redV rac_valuesAndChangesForKeyPath:@ "center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) { NSLog(@ "%@" ,x); }]; 3 监听事件: rac_signalForControlEvents:用于监听某个事件。 // 把按钮点击事件转换为信号,点击按钮,就会发送信号 [[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { NSLog(@ "按钮被点击了" ); }]; 4 代替通知: rac_addObserverForName:用于监听某个通知。 [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) { NSLog(@ "键盘弹出" ); }]; 5 监听文本框文字改变: rac_textSignal:只要文本框发出改变就会发出这个信号。 [_textField.rac_textSignal subscribeNext:^(id x) { NSLog(@ "文字改变了%@" ,x); }]; |
6、常见宏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 、RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定。 // 只要文本框文字改变,就会修改label的文字 RAC(self.labelView,text) = _textField.rac_textSignal; 2 、RACObserve(self, name):监听某个对象的某个属性,返回的是信号。 [RACObserve(self.view, center) subscribeNext:^(id x) { NSLog(@ "%@" ,x); }]; 3 、RACTuplePack:把数据包装成RACTuple(元组类) // 把参数中的数据包装成元组 RACTuple *tuple = RACTuplePack(@ 10 ,@ 20 ); 4 、RACTupleUnpack:把RACTuple(元组类)解包成对应的数据。 // 把参数中的数据包装成元组 RACTuple *tuple = RACTuplePack(@ "xmg" ,@ 20 ); // 解包元组,会把元组的值,按顺序给参数里面的变量赋值 // name = @"xmg" age = @20 RACTupleUnpack(NSString *name,NSNumber *age) = tuple; |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端