ReactiveCocoa常见操作介绍 ReactiveCocoa操作须知
所有的信号RACSignal
都可以进行操作处理,因为所有操作方法都定义在RACStream.h中,因此只要继承RACStream就有了操作处理方法。
ReactiveCocoa操作思想
运用的是Hook(钩子)思想,Hook是一种用于改变API(应用程序编程接口:方法)执行结果的技术.
Hook用处:截获API调用的技术。
Hook原理:在每次调用一个API返回结果之前,先执行你自己的方法,改变结果的输出
高级操作 ReactiveCocoa核心方法bind
ReactiveCocoa
操作的核心方法是bind
(绑定),而且RAC中核心开发方式,也是绑定,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。
在开发中很少使用bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其他方法,底层都是调用bind,用法比bind简单.
bind方法简单介绍和使用
需求: 监听文本框的内容, 每次输出的时候, 在内容后面品尚字符串"jun"
, 并显示在label
上
方式一: 在返回结果后, 拼接字符串
1 2 3 4 5 6 @weakify(self ) [_textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) { @strongify(self ) self .showLabel.text = [NSString stringWithFormat:@"%@+%@" , x, @"jun" ]; }];
方式二: 在返回结果前, 拼接字符串, 用bind方法操作
1 2 3 4 5 6 7 [[_textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{ return ^RACSignal *(id value, BOOL *stop){ return [RACReturnSignal return :[NSString stringWithFormat:@"输出: %@" , value]]; }; }] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }];
bind
方法介绍
bind
方法参数:需要传入一个返回值是RACStreamBindBlock
的block
参数
RACStreamBindBlock
是一个block
的类型,返回值是信号,参数(value,stop)
,因此参数的block
返回值也是一个block
如下:
1 2 typedef RACSignal * _Nullable (^RACSignalBindBlock)(ValueType _Nullable value, BOOL *stop);
RACStreamBindBlock
:
参数一(value): 表示接收到信号的原始值,还没做处理
参数二*stop
: 用来控制绑定Block
,如果*stop
= yes,那么就会结束绑定。
返回值:信号,做好处理,在通过这个信号返回出去,一般使用RACReturnSignal
,需要手动导入头文件RACReturnSignal.h
1 2 3 4 5 @interface RACReturnSignal <__covariant ValueType > : RACSignal <ValueType >+ (RACSignal<ValueType> *)return :(ValueType)value; @end
bind方法使用步骤:
传入一个返回值RACStreamBindBlock
的block
描述一个RACStreamBindBlock
类型的bindBlock
作为block
的返回值。
描述一个返回结果的信号,作为bindBlock
的返回值。
注意:在bindBlock
中做信号结果的处理
bind底层实现:
源信号调用bind,会重新创建一个绑定信号。
当绑定信号被订阅,就会调用绑定信号中的didSubscribe
,生成一个bindingBlock
。
当源信号有内容发出,就会把内容传递到bindingBlock
处理,调用bindingBlock(value,stop)
调用bindingBlock(value,stop)
,会返回一个内容处理完成的信号(RACReturnSignal)
。
订阅RACReturnSignal
,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来
映射(flattenMap,Map)
flattenMap
把源信号的内容映射成一个新的信号,信号可以是任意类型
flattenMap
使用步骤:
传入一个block
,block
类型是返回值RACStream
,参数value
参数value
就是源信号的内容,拿到源信号的内容做处理
包装成RACReturnSignal
信号,返回出去
flattenMap
底层实现:
0.flattenMap
内部调用bind
方法实现的,flattenMap
中block
的返回值,会作为bind
中bindBlock
的返回值。
1.当订阅绑定信号,就会生成bindBlock
。
2.当源信号发送内容,就会调用bindBlock(value, *stop)
3.调用bindBlock
,内部就会调用flattenMap
的block
,flattenMap
的block
作用:就是把处理好的数据包装成信号
4.返回的信号最终会作为bindBlock
中的返回信号,当做bindBlock
的返回信号。
5.订阅bindBlock
的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来
1 2 3 4 5 6 7 8 9 10 11 12 - (__kindof RACStream *)flattenMap:(__kindof RACStream * (^)(id value))block { Class class = self .class; return [[self bind:^{ return ^(id value, BOOL *stop) { id stream = block(value) ?: [class empty]; NSCAssert ([stream isKindOfClass:RACStream.class], @"Value returned from -flattenMap: is not a stream: %@" , stream); return stream; }; }] setNameWithFormat:@"[%@] -flattenMap:" , self .name]; }
简单使用
1 2 3 4 5 6 7 8 9 10 11 @weakify(self ) [[_textField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) { return [RACReturnSignal return :[NSString stringWithFormat:@"flat输出: %@" , value]]; }] subscribeNext:^(id _Nullable x) { @strongify(self ) self .showLabel.text = x; NSLog (@"%@" , x); }];
Map Map作用:把源信号的值映射成一个新的值
Map
使用步骤:
传入一个block
,类型是返回对象,参数是value
value
就是源信号的内容,直接拿到源信号的内容做处理
把处理好的内容,直接返回就好了,不用包装成信号,返回的值,就是映射的值。
Map
底层实现:
Map
底层其实是调用flatternMap
, Map中block
中的返回的值会作为flatternMap
中block中的值。
当订阅绑定信号,就会生成bindBlock
。
当源信号发送内容,就会调用bindBlock(value, *stop)
调用bindBlock
,内部就会调用flattenMap
的block
flattenMap
的block
内部会调用Map
中的block
,把Map中的block
返回的内容包装成返回的信号。
返回的信号最终会作为bindBlock
中的返回信号,当做bindBlock
的返回信号。
订阅bindBlock
的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来
1 2 3 4 5 6 7 8 9 - (__kindof RACStream *)map:(id (^)(id value))block { NSCParameterAssert (block != nil ); Class class = self .class; return [[self flattenMap:^(id value) { return [class return :block(value)]; }] setNameWithFormat:@"[%@] -map:" , self .name]; }
简单使用
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 [[_textField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) { return [NSString stringWithFormat:@"map输出: %@" , value]; }] subscribeNext:^(id _Nullable x) { @strongify(self ) self .showLabel.text = x; NSLog (@"%@" , x); }]; NSArray *arr = @[@"2" , @"3" , @"a" , @"g" ];RACSequence *sequence = [arr.rac_sequence map:^id _Nullable(id _Nullable value) { return [NSString stringWithFormat:@"-%@-" , value]; }]; NSLog (@"%@" , [sequence array]);
FlatternMap
和 Map
的区别
FlatternMap
中的Block
返回信号。
Map
中的Block
返回对象。
开发中,如果信号发出的值不是信号,映射一般使用Map
开发中,如果信号发出的值是信号,映射一般使用FlatternMap
信号中信号
当一个信号需要返回另一个信号中的值的时候
让我们来看看下面这个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #pragma 信号中信号 - (void )singleAndSingle { RACSubject *sonSingle = [RACSubject subject]; RACSubject *single = [RACSubject subject]; [[sonSingle flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) { return value; }] subscribeNext:^(id _Nullable x) { NSLog (@"输出: %@" , x); }]; [sonSingle sendNext:single]; [single sendNext:@123 ]; }
组合 concat 按照某一固定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - (void )setConcatAction { RACSubject *subjectA = [RACSubject subject]; RACSubject *subjectB = [RACReplaySubject subject]; NSMutableArray *array = [NSMutableArray array]; [subjectA subscribeNext:^(id _Nullable x) { [array addObject:x]; }]; [subjectB subscribeNext:^(id _Nullable x) { [array addObject:x]; }]; [subjectB sendNext:@"B" ]; [subjectA sendNext:@"A" ]; [subjectA sendCompleted]; NSLog (@"%@" , array); }
很明显, 上述的结果并未达到我们的需求: 限制性A, 在执行B
下面我们看看使用concat
后的执行情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - (void )setConcatAction { RACSubject *subC = [RACSubject subject]; RACSubject *subD = [RACReplaySubject subject]; NSMutableArray *array2 = [NSMutableArray array]; [[subC concat:subD] subscribeNext:^(id _Nullable x) { [array2 addObject:x]; }]; [subD sendNext:@"D" ]; [subC sendNext:@"C" ]; [subC sendCompleted]; NSLog (@"%@" , array2); }
可以看到, 输出的结果和我们预想的一样, 顺序输出
那么, concat
的底层到底是如何实现的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - (RACSignal *)concat:(RACSignal *)signal { return [[RACSignal createSignal:^(id <RACSubscriber> subscriber) { RACCompoundDisposable *compoundDisposable = [[RACCompoundDisposable alloc] init]; RACDisposable *sourceDisposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ RACDisposable *concattedDisposable = [signal subscribe:subscriber]; [compoundDisposable addDisposable:concattedDisposable]; }]; [compoundDisposable addDisposable:sourceDisposable]; return compoundDisposable; }] setNameWithFormat:@"[%@] -concat: %@" , self .name, signal]; }
concat
底层实现:
当拼接信号被订阅,就会调用拼接信号的didSubscribe
didSubscribe
中,会先订阅第一个源信号subjectA
会执行第一个源信号subjectA
的didSubscribe
第一个源信号subjectA
的didSubscribe
中发送值,就会调用第一个源信号subjectA
订阅者的nextBlock
, 通过拼接信号的订阅者把值发送出来.
第一个源信号subjectA
的didSubscribe
中发送完成,就会调用第一个源信号subjectA
订阅者的completedBlock
,订阅第二个源信号subjectB
这时候才激活subjectB
订阅第二个源信号subjectB
,执行第二个源信subjectB
号的didSubscribe
第二个源信号subjectB
的didSubscribe
中发送值,就会通过拼接信号的订阅者把值发送出来.
then 用于连接两个信号,当第一个信号完成,才会连接then返回的信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - (RACSignal *)then:(RACSignal * (^)(void ))block { NSCParameterAssert (block != nil ); return [[[self ignoreValues] concat:[RACSignal defer:block]] setNameWithFormat:@"[%@] -then:" , self .name]; } - (RACSignal *)ignoreValues { return [[self filter:^(id _) { return NO ; }] setNameWithFormat:@"[%@] -ignoreValues" , self .name]; }
实现原理
底层会调用filter
过滤掉本身信号发出的值(filter
后面会讲到)
然后再使用concat
连接then
返回的信号
下面是测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - (void )setThenAction { RACSubject *subjectA = [RACReplaySubject subject]; RACSubject *subjectB = [RACReplaySubject subject]; [subjectA sendNext:@"A" ]; [subjectA sendCompleted]; [subjectB sendNext:@"B" ]; [[subjectA then:^RACSignal * _Nonnull{ return subjectB; }] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; }
merge 把多个信号合并为一个信号,任何一个信号有新值的时候就会调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - (RACSignal *)merge:(RACSignal *)signal { return [[RACSignal merge:@[ self , signal ]] setNameWithFormat:@"[%@] -merge: %@" , self .name, signal]; } + (RACSignal *)merge:(id <NSFastEnumeration >)signals { NSMutableArray *copiedSignals = [[NSMutableArray alloc] init]; for (RACSignal *signal in signals) { [copiedSignals addObject:signal]; } return [[[RACSignal createSignal:^ RACDisposable * (id <RACSubscriber> subscriber) { for (RACSignal *signal in copiedSignals) { [subscriber sendNext:signal]; } [subscriber sendCompleted]; return nil ; }] flatten] setNameWithFormat:@"+merge: %@" , copiedSignals]; }
底层实现
1.合并信号被订阅的时候,就会遍历所有信号,并且发出这些信号。
2.每发出一个信号,这个信号就会被订阅
3.也就是合并信号一被订阅,就会订阅里面所有的信号。
4.只要有一个信号被发出就会被监听。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 - (void )setMergeAction { RACSubject *subjectA = [RACSubject subject]; RACSubject *subjectB = [RACSubject subject]; RACSubject *subjectC = [RACSubject subject]; RACSignal *single = [[subjectA merge:subjectB] merge:subjectC]; [single subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subjectA sendNext:@"A" ]; [subjectC sendNext:@"C" ]; [subjectB sendNext:@"B" ]; }
zipWith 把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件
底层实现:
1.定义压缩信号,内部就会自动订阅subjectA
,subjectB
2.每当subjectA
或者subjectB
发出信号,就会判断subjectA
,subjectB
有没有发出个信号,有就会把最近发出的信号都包装成元组发出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 - (void )setZipwithAction { RACSubject *subjectA = [RACSubject subject]; RACSubject *subjectB = [RACSubject subject]; RACSignal *single = [subjectA zipWith:subjectB]; [single subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subjectA sendNext:@"A" ]; [subjectB sendNext:@"B" ]; }
combineLatest
将多个信号合并起来,并且拿到各个信号的最新的值
必须每个合并的信号至少都有过一次sendNext
,才会触发合并的信号
这里我们考虑这样一个需求: 在登录页面, 只有在账号密码都输入的情况下, 登录按钮才可点击, 否则不可点击
正常情况下我们需要监听每一个文本框的输入
下面我们来看一下combineLatest
控制登录按钮是否可点击
1 2 3 4 5 6 7 8 9 10 - (void )setCombineLatest { RACSignal *single = [_accountText.rac_textSignal combineLatestWith:_passwordText.rac_textSignal]; [single subscribeNext:^(id _Nullable x) { RACTupleUnpack(NSString *account, NSString *password) = x; _loginButton.enabled = account.length > 0 && password.length > 0 ; }]; }
底层实现:
1.当组合信号被订阅,内部会自动订阅两个信号,必须两个信号都发出内容,才会被触发。(而zip, 是两个信号同事发出内容, 才会触发)
2.把两个信号组合成元组发出。
reduce 聚合:用于信号发出是元组的内容,把信号发出元组的值聚合成一个值
这里我们把上面的代码, 使用RACSingle
的一个类方法优化一下
1 2 3 4 5 6 7 8 9 10 - (void )setReduceAction { RACSignal *single = [RACSignal combineLatest:@[_accountText.rac_textSignal, _passwordText.rac_textSignal] reduce:^id (NSString *account, NSString *password){ return @(account.length > 0 && password.length > 0 ); }]; [single subscribeNext:^(id _Nullable x) { _loginButton.enabled = [x boolValue]; }]; }
RACSingle
类方法
参数一: (id<NSFastEnumeration>)
类型
NSFastEnumeration
我们在上一篇文章ReactiveCocoa之集合使用详解02 中简单介绍过
NSFastEnumeration
: 是一个协议, 所有遵循该协议的类, 均可视为一个数组, 例如NSArray
故这里, 应该传一个包含RACSingle
信号的数组
参数二: (RACGenericReduceBlock)reduceBlock
是一个black
1 2 3 typedef ValueType _Nonnull (^RACGenericReduceBlock)();
这里用一个宏, 急需将上面的代码简化一下
1 2 3 4 5 6 - (void )setReduceAction { RAC(_loginButton, enabled) = [RACSignal combineLatest:@[_accountText.rac_textSignal, _passwordText.rac_textSignal] reduce:^id (NSString *account, NSString *password){ return @(account.length > 0 && password.length > 0 ); }]; }
上面用到了一个宏RAC
, 这里暂不赘述, 以后会集中整理一下 RAC中的宏, 具体实现如下
1 2 3 4 5 6 7 8 #define RAC(TARGET, ...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \ (RAC_(TARGET, __VA_ARGS__, nil)) \ (RAC_(TARGET, __VA_ARGS__)) #define RAC_(TARGET, KEYPATH, NILVALUE) \ [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)]
过滤 filter 过滤信号, 过滤掉不符合条件的信号
1 2 3 4 5 6 7 8 9 10 11 - (void ) filterAction{ [[_accountText.rac_textSignal filter:^BOOL (NSString * _Nullable value) { return value.length == 11 ; }]subscribeNext:^(NSString * _Nullable x) { NSLog (@"filter = %@" , x); }]; }
filter
底层是调用的flatMap
方法, 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 - (__kindof RACStream *)filter:(BOOL (^)(id value))block { NSCParameterAssert (block != nil ); Class class = self .class; return [[self flattenMap:^ id (id value) { if (block(value)) { return [class return :value]; } else { return class .empty; } }] setNameWithFormat:@"[%@] -filter:" , self .name]; }
ignore 忽略掉某些特定值的信号
1 2 3 4 5 6 7 8 9 10 11 12 - (void )setIgnoreAction { [[_accountText.rac_textSignal ignore:@"m" ] subscribeNext:^(NSString * _Nullable x) { NSLog (@"ignore = %@" , x); }]; [[_passwordText.rac_textSignal ignoreValues] subscribeNext:^(id _Nullable x) { NSLog (@"allIgnore = %@" , x); }]; }
ignore
方法的底层都是调用的filter
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 - (__kindof RACStream *)ignore:(id )value { return [[self filter:^ BOOL (id innerValue) { return innerValue != value && ![innerValue isEqual:value]; }] setNameWithFormat:@"[%@] -ignore: %@" , self .name, RACDescription(value)]; } - (RACSignal *)ignoreValues { return [[self filter:^(id _) { return NO ; }] setNameWithFormat:@"[%@] -ignoreValues" , self .name]; }
distinctUntilChanged
当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。
在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - (void )setdistinctUntilChanged { RACSubject *subject = [RACSubject subject]; [[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) { NSLog (@"distinctUntilChanged = %@" , x); }]; [subject sendNext:@12 ]; [subject sendNext:@12 ]; [subject sendNext:@23 ]; }
distinctUntilChanged
底层是调用的bind
高级用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - (__kindof RACStream *)distinctUntilChanged { Class class = self .class; return [[self bind:^{ __block id lastValue = nil ; __block BOOL initial = YES ; return ^(id x, BOOL *stop) { if (!initial && (lastValue == x || [x isEqual:lastValue])) return [class empty]; initial = NO ; lastValue = x; return [class return :x]; }; }] setNameWithFormat:@"[%@] -distinctUntilChanged" , self .name]; }
take 从开始一共取N次的信号, 当遇到sendCompleted
语句执行时, 会提前停止发送信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 - (void )setTakeAndTakeLast { RACSubject *subject1 = [RACSubject subject]; [[subject1 take:2 ] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subject1 sendNext:@1 ]; [subject1 sendNext:@2 ]; [subject1 sendCompleted]; [subject1 sendNext:@3 ]; } [subject1 sendNext:@1 ]; [subject1 sendCompleted]; [subject1 sendNext:@2 ]; [subject1 sendNext:@3 ];
takeLast 取调用sendCompleted
之前的N次信号,前提条件,订阅者必须调用sendCompleted
,否则不会执行任何操作
1 2 3 4 5 6 7 8 9 10 11 12 - (void )setTakeAndTakeLast { RACSubject *subject1 = [RACSubject subject]; [[subject1 takeLast:2 ] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subject1 sendNext:@1 ]; [subject1 sendNext:@2 ]; [subject1 sendNext:@3 ]; [subject1 sendCompleted]; }
takeUntil 只要传入的信号发送完成或者subject2
开始发送信号的时候,就不会再接收信号的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - (void )setTakeAndTakeLast { RACSubject *subject1 = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; [[subject1 takeUntil:subject2] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subject1 sendNext:@11 ]; [subject1 sendNext:@12 ]; [subject1 sendNext:@13 ]; [subject2 sendNext:@"21" ]; [subject2 sendNext:@"22" ]; }
switchToLatest
主要用于信号的信号, 有时候也会发出信号, 会在信号的信号中获取其发送的最新的信号
方法的底层是调用了flattenMap
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 - (RACSignal *)switchToLatest { return [[RACSignal createSignal:^(id <RACSubscriber> subscriber) { RACMulticastConnection *connection = [self publish]; RACDisposable *subscriptionDisposable = [[connection.signal flattenMap:^(RACSignal *x) { NSCAssert (x == nil || [x isKindOfClass:RACSignal.class], @"-switchToLatest requires that the source signal (%@) send signals. Instead we got: %@" , self , x); return [x takeUntil:[connection.signal concat:[RACSignal never]]]; }] subscribe:subscriber]; RACDisposable *connectionDisposable = [connection connect]; return [RACDisposable disposableWithBlock:^{ [subscriptionDisposable dispose]; [connectionDisposable dispose]; }]; }] setNameWithFormat:@"[%@] -switchToLatest" , self .name]; }
下面我们看一下具体的使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - (void )setswitchToLatest { RACSubject *subject1 = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; [[subject1 switchToLatest] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subject1 sendNext:subject2]; [subject2 sendNext:@"信号中信号" ]; }
skip 跳过N个信号后, 再开始订阅信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - (void )setSkipAction { RACSubject *subject = [RACSubject subject]; [[subject skip:2 ] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subject sendNext:@1 ]; [subject sendNext:@2 ]; [subject sendNext:@3 ]; [subject sendNext:@4 ]; }
定时操作 interval 定时器, 每隔一段时间发出信号
1 2 3 4 [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) { NSLog (@"定时器" ); }];
其中RACScheduler
是RAC
中管理线程的类
delay 延迟一段时间都发送信号
1 2 3 4 5 6 7 [[[RACSignal createSignal:^RACDisposable * _Nullable(id <RACSubscriber> _Nonnull subscriber) { [subscriber sendNext:@"delay" ]; return nil ; }] delay:2 ] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }];
timeout 超时, 可以让一个信号在一定时间后自动报错
1 2 3 4 5 6 7 8 9 10 11 RACSignal *single = [[RACSignal createSignal:^RACDisposable * _Nullable(id <RACSubscriber> _Nonnull subscriber) { return nil ; }] timeout:2 onScheduler:[RACScheduler currentScheduler]]; [single subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); } error:^(NSError * _Nullable error) { NSLog (@"%@" , error); }];
重复操作 retry 重试 :只要失败,就会重新执行创建信号中的block,直到成功.
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 - (void )setResertAction { __block int i = 0 ; [[[RACSignal createSignal:^RACDisposable * _Nullable(id <RACSubscriber> _Nonnull subscriber) { if (i == 5 ) { [subscriber sendNext:@12 ]; } else { NSLog (@"发生错误" ); [subscriber sendError:nil ]; } i++; return nil ; }] retry] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); } error:^(NSError * _Nullable error) { NSLog (@"%@" , error); }]; }
replay 重放:当一个信号被多次订阅,反复播放内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 RACSignal *single = [[RACSignal createSignal:^RACDisposable * _Nullable(id <RACSubscriber> _Nonnull subscriber) { [subscriber sendNext:@23 ]; [subscriber sendNext:@34 ]; return nil ; }] replay]; [single subscribeNext:^(id _Nullable x) { NSLog (@"第一次订阅-%@" , x); }]; [single subscribeNext:^(id _Nullable x) { NSLog (@"第二次订阅-%@" , x); }];
throttle 节流:当某个信号发送比较频繁时,可以使用节流, 在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 RACSubject *subject = [RACSubject subject]; [[subject throttle:0.001 ] subscribeNext:^(id _Nullable x) { NSLog (@"%@" , x); }]; [subject sendNext:@10 ]; [subject sendNext:@11 ]; [subject sendNext:@12 ]; [subject sendNext:@13 ]; [subject sendNext:@14 ]; [subject sendNext:@15 ]; [subject sendNext:@16 ]; [subject sendNext:@17 ]; [subject sendNext:@18 ];
以上就是RAC中的一些常用的高级用用法具体讲解和使用示例
如有不足之处, 还请多多指教, 后期会持续更新相关知识点
下面是RAC相关的两篇文章