RAC在iOS的实际开发中的用法,此文将从以下几方面讲解
学习 ReactiveCocoa 的一些方法总结
- RACSignal
- RACSubject
- RACSequence
- RACMulticastConnection
- RACCommand
- RAC常用宏
- RAC-bind
- RAC-过滤
- RAC-映射
- RAC-组合
RACSignal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"ws"];
return [RACDisposable disposableWithBlock:^{ NSLog(@"取消订阅"); }]; }];
RACDisposable *disposable = [signal subscribeNext:^(id x) {
NSLog(@"======%@", x); }];
[disposable dispose];
|
总结
- .核心:
- .核心:信号类
- .信号类的作用:只要有数据改变就会把数据包装成信号传递出去
- .只要有数据改变就会有信号发出
- .数据发出,并不是信号类发出,信号类不能发送数据
- .使用方法:
- .创建信号
- .订阅信号
- .实现思路:
- .当一个信号被订阅,创建订阅者,并把nextBlock保存到订阅者里面。
- .创建的时候会返回 [RACDynamicSignal createSignal:didSubscribe];
- .调用RACDynamicSignal的didSubscribe
- .发送信号[subscriber sendNext:value];
- .拿到订阅者的nextBlock调用
*/
RACSubject
RACSubject 在使用中我们可以完全代替代理,代码简介方法。具体代码请看demo中的RACSubject。
总结
我们完全可以用RACSubject代替代理/通知,确实方便许多
这里我们点击TwoViewController的pop的时候 将字符串”ws”传给了ViewController的button的title。
步骤:
1
| RACSubject *subject = [RACSubject subject];
|
1 2 3 4 5
| [subject subscribeNext:^(id x) {
NSLog(@"%@",x); }];
|
1
| [subject sendNext:value];
|
- 注意
RACSubject和RACReplaySubject的区别
RACSubject必须要先订阅信号之后才能发送信号, 而RACReplaySubject可以先发送信号后订阅.
RACSubject 代码中体现为:先走TwoViewController的sendNext,后走ViewController的subscribeNext订阅
RACReplaySubject 代码中体现为:先走ViewController的subscribeNext订阅,后走TwoViewController的sendNext
可按实际情况各取所需。
RACSequence
使用场景—: 可以快速高效的遍历数组和字典。
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
| NSString *path = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; [dictArr.rac_sequence.signal subscribeNext:^(id x) { NSLog(@"%@", x); } error:^(NSError *error) { NSLog(@"===error==="); } completed:^{ NSLog(@"ok---完毕"); }];
也可以使用宏
NSDictionary *dict = @{@"key":@1, @"key2":@2}; [dict.rac_sequence.signal subscribeNext:^(id x) { NSLog(@"%@", x); NSString *key = x[0]; NSString *value = x[1];
RACTupleUnpack(NSString *key, NSString *value) = x; NSLog(@"%@ %@", key, value); } error:^(NSError *error) { NSLog(@"===error"); } completed:^{ NSLog(@"-----ok---完毕"); }];
|
RACMulticastConnection
当有多个订阅者,但是我们只想发送一个信号的时候怎么办?这时我们就可以用RACMulticastConnection,来实现。代码示例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"发送请求啦");
[subscriber sendNext:@"ws"]; return nil; }]; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }]; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }]; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"发送请求啦");
[subscriber sendNext:@"ws"]; return nil; }];
RACMulticastConnection *connection = [signal publish]; [connection.signal subscribeNext:^(id x) { NSLog(@"%@", x); }]; [connection.signal subscribeNext:^(id x) { NSLog(@"%@", x); }]; [connection.signal subscribeNext:^(id x) { NSLog(@"%@", x); }];
[connection connect];
|
RACCommand
- RACCommand:RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,比如看事件有没有执行完毕
- 使用场景:监听按钮点击,网络请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@",input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"执行命令产生的数据"]; return nil; }]; }];
RACSignal *signal =[command execute:@2];
[signal subscribeNext:^(id x) { NSLog(@"%@",x); }];
|
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
|
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@",input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"执行命令产生的数据"]; return nil; }]; }];
[command.executionSignals subscribeNext:^(RACSignal *x) { [x subscribeNext:^(id x) { NSLog(@"%@", x); }];
}];
[command execute:@2];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@", input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"发送信号"]; return nil; }]; }];
[command.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"%@", x); }];
[command execute:@3];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
RACSubject *signalofsignals = [RACSubject subject]; RACSubject *signalA = [RACSubject subject];
[signalofsignals.switchToLatest subscribeNext:^(id x) { NSLog(@"%@", x); }];
[signalofsignals sendNext:signalA]; [signalA sendNext:@4];
|
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
|
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@", input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"执行命令产生的数据"];
[subscriber sendCompleted]; return nil; }]; }];
[command.executing subscribeNext:^(id x) { if ([x boolValue] == YES) { NSLog(@"当前正在执行%@", x); }else {
NSLog(@"执行完成/没有执行"); } }];
[command execute:@1];
|
RAC常用宏
RAC有许多强大而方便的宏。如下
1 2 3 4 5 6
|
RAC(self.label, text) = self.textField.rac_textSignal;
|
1 2 3 4 5 6 7 8
|
[RACObserve(self.view, center) subscribeNext:^(id x) { NSLog(@"%@", x); }];
|
1 2 3 4 5
| RAC(self.label, text) = self.textField.rac_textSignal; [RACObserve(self.label, text) subscribeNext:^(id x) { NSLog(@"====label的文字变了"); }];
|
1 2 3 4 5 6 7 8 9 10 11
|
@weakify(self) RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { @strongify(self) NSLog(@"%@",self.view); return nil; }]; _signal = signal; 使用 @weakify(self)和@strongify(self)来避免循环引用
|
1 2 3 4 5 6 7 8 9 10 11
|
RACTuple *tuple = RACTuplePack(@1,@2,@4);
RACTupleUnpack_(NSNumber *num1, NSNumber *num2, NSNumber * num3) = tuple;
NSLog(@"%@ %@ %@", num1, num2, num3);
|
RAC-bind
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject bind:^RACStreamBindBlock{
return ^RACSignal *(id value, BOOL *stop){
value = @3; NSLog(@"接受到源信号的内容:%@", value);
return [RACReturnSignal return:value]; }; }];
[bindSignal subscribeNext:^(id x) {
NSLog(@"接收到绑定信号处理完的信号:%@", x); }];
[subject sendNext:@"123"];
|
- 总结
- bind(绑定)的使用思想和Hook的一样—> 都是拦截API从而可以对数据进行操作,,而影响返回数据。
- 发送信号的时候会来到30行的block。在这个block里我们可以对数据进行一些操作,那么35行打印的value和订阅绑定信号后的value就会变了。变成什么样随你喜欢喽。
RAC-过滤
- 有时候我们想要过滤一些信号,这时候我们便可以用RAC的过滤方法。过滤方法有好多种,如下代码,从不同情况下进行了分析。
1 2 3 4 5 6 7 8 9
|
RACSubject *subject = [RACSubject subject]; [[subject skip:2] subscribeNext:^(id x) { NSLog(@"%@", x); }]; [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3];
|
1 2 3 4 5 6 7 8 9
| RACSubject *subject = [RACSubject subject]; [[subject distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@2];
|
1 2 3 4 5 6 7 8 9
| RACSubject *subject = [RACSubject subject]; [[subject take:2] subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3];
|
1 2 3 4 5 6 7 8 9 10 11
|
RACSubject *subject = [RACSubject subject]; [[subject takeLast:2] subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3]; [subject sendCompleted];
|
1 2 3 4 5 6 7 8 9 10 11 12
| RACSubject *subject = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; [[subject takeUntil:subject2] subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@1]; [subject sendNext:@2]; [subject2 sendNext:@3];
[subject sendNext:@4];
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
RACSubject *subject = [RACSubject subject];
RACSignal *ignoreSignal = [subject ignore:@2];
[ignoreSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@2];
|
1 2 3 4 5 6 7 8 9
|
[[self.textField.rac_textSignal filter:^BOOL(id value) {
return [value length] > 5;
}] subscribeNext:^(id x) { NSLog(@"%@", x); }];
|
RAC-映射
- RAC的映射在实际开发中有什么用呢?比如我们想要拦截服务器返回的数据,给数据拼接特定的东西或想对数据进行操作从而更改返回值,类似于这样的情况下,我们便可以考虑用RAC的映射,实例代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| - (void)map {
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject map:^id(id value) {
return [NSString stringWithFormat:@"ws:%@", value]; }];
[bindSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@"123"];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| - (void)flatMap {
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject flattenMap:^RACStream *(id value) {
return [RACReturnSignal return:value];
}];
[bindSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];
[subject sendNext:@"123"];
}
|
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
| - (void)flattenMap2 {
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:@"123"]; }
|
RAC-组合
- 把多个信号聚合成你想要的信号,使用场景—-:比如-当多个输入框都有值的时候按钮才可点击。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| - (void)combineLatest {
RACSignal *combinSignal = [RACSignal combineLatest:@[self.accountField.rac_textSignal, self.pwdField.rac_textSignal] reduce:^id(NSString *account, NSString *pwd){
NSLog(@"%@ %@", account, pwd); return @(account.length && pwd.length); }];
RAC(self.loginBtn, enabled) = combinSignal; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - (void)zipWith {
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
RACSignal *zipSignal = [signalA zipWith:signalB]; [zipSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];
[signalA sendNext:@1]; [signalB sendNext:@2];
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
- (void)merge {
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
RACSignal *mergeSignal = [signalA merge:signalB];
[mergeSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];
[signalB sendNext:@"下部分"]; [signalA sendNext:@"上部分"]; }
|
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
| - (void)then {
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"----发送上部分请求---afn");
[subscriber sendNext:@"上部分数据"]; [subscriber sendCompleted]; return nil; }];
RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"--发送下部分请求--afn"); [subscriber sendNext:@"下部分数据"]; return nil; }];
RACSignal *thenSignal = [signalA then:^RACSignal *{
return signalsB; }];
[thenSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];
}
|
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
| - (void)concat {
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"上部分数据"]; [subscriber sendCompleted]; return nil; }];
RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"下部分数据"]; return nil; }];
RACSignal *concatSignal = [signalA concat:signalsB];
[concatSignal subscribeNext:^(id x) { NSLog(@"%@",x); }];
}
|