RAC高階函數(shù)
0. bind
- bind方法使用步驟:
- 傳入一個返回值RACStreamBindBlock的block。
- 描述一個RACStreamBindBlock類型的bindBlock作為block的返回值。
- 描述一個返回結(jié)果的信號,作為bindBlock的返回值。
RACStreamBindBlock是一個block的類型,返回值是信號,參數(shù)(value,stop),因此參數(shù)的block返回值也是一個block。
RACStreamBindBlock:
參數(shù)一(value):表示接收到信號的原始值,還沒做處理
參數(shù)二(stop):用來控制綁定Block,如果stop = yes,那么就會結(jié)束綁定。
返回值:信號,做好處理,在通過這個信號返回出去,一般使用RACReturnSignal,需要手動導(dǎo)入頭文件RACReturnSignal.h。
- bind底層原理
- 源信號調(diào)用bind,會重新創(chuàng)建一個綁定信號。
- 當(dāng)綁定信號被訂閱,就會調(diào)用綁定信號中的didSubscribe,生成一個bindingBlock。
- 當(dāng)源信號有內(nèi)容發(fā)出,就會把內(nèi)容傳遞到bindingBlock處理,調(diào)用bindingBlock(value,stop)
- 調(diào)用bindingBlock(value,stop),會返回一個內(nèi)容處理完成的信號(RACReturnSignal)。
- 訂閱RACReturnSignal,就會拿到綁定信號的訂閱者,把處理完成的信號內(nèi)容發(fā)送出來。
[[self.tf.rac_textSignal bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal * (NSString * __nullable value, BOOL *stop) {
if (value.length >= 11) {
[self.tf resignFirstResponder];
*stop = YES;
}
return [RACReturnSignal return:value];
};
}] subscribeNext:^(id _Nullable x) {
NSLog(@"bind:%@", x);
}];
1. 信號映射
map
// 輸入一個11位數(shù)的手機(jī)號,map中在前面添加+86,超過11位時(shí)next信號就訂閱不到了。
[[self.tf.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
return value.length <= 11 ? [NSString stringWithFormat:@"+86 %@", value] : nil;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"map:%@", x);
}];
flattenMap
- flattenMap底層實(shí)現(xiàn):
- flattenMap內(nèi)部調(diào)用bind方法實(shí)現(xiàn)的,flattenMap中block的返回值,會作為bind中bindBlock的返回值。
- 當(dāng)訂閱綁定信號,就會生成bindBlock。
- 當(dāng)源信號發(fā)送內(nèi)容,就會調(diào)用bindBlock(value, *stop)
- 調(diào)用bindBlock,內(nèi)部就會調(diào)用flattenMap的block,flattenMap的block作用:就是把處理好的數(shù)據(jù)包裝成信號。
- 返回的信號最終會作為bindBlock中的返回信號。
- 訂閱bindBlock的返回信號,就會拿到綁定信號的訂閱者,把處理完成的信號內(nèi)容發(fā)送出來。
[[self.tf.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
// value為源信號的內(nèi)容,處理完后包裝成RACReturnSignal返回。
NSString *mapValue = [NSString stringWithFormat:@"+86 %@", value];
return value.length <= 11 ? [RACReturnSignal return:mapValue] : [RACSignal empty];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"flattenMap:%@", x);
}];
2. 信號過濾
filter
[[self.tf.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
BOOL isStop = value.length > 11;
if (isStop) {
self.tf.text = [value substringToIndex:11];
}
return !isStop;
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"filter:%@", x);
}];
ignore
[[self.tf.rac_textSignal ignore:@"13123456789"] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"ignore:%@", x);
}];
distinctUntilChanged
- 當(dāng)上一次的值和當(dāng)前的值有明顯的變化就會發(fā)出信號,否則會被忽略掉。
- 在開發(fā)中,刷新UI經(jīng)常使用,只有兩次數(shù)據(jù)不一樣才需要刷新
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"game over");
}];
}] distinctUntilChanged] subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱到:%@", x);
}];
輸出:
訂閱到:1
訂閱到:2
訂閱到:3
game over
3. 信號合并
combineLatest
- 將多個信號合并起來,并且拿到各個信號的最新的值,必須每個合并的signal至少都有過一次sendNext,才會觸發(fā)合并的信號。
區(qū)別于zipWith,zipWith兩個信號都要有記錄,如果記錄的信號觸發(fā)過了就不再觸發(fā)
zipWith:記錄每一次信號
combineLatestWith:記錄最后一次的信號
RACSignal *signalA = [self.tf rac_textSignal];
RACSignal *signalB = [self.btn rac_signalForControlEvents:UIControlEventTouchUpInside];
RACSignal *combineSignal = [signalA combineLatestWith:signalB];
[combineSignal subscribeNext:^(id _Nullable x) {
NSLog(@"combine:%@", x);
}];
- 底層實(shí)現(xiàn):
- 當(dāng)組合信號被訂閱,內(nèi)部會自動訂閱signalA,signalB,必須兩個信號都發(fā)出內(nèi)容,才會被觸發(fā)。
- 并且把兩個信號組合成元組發(fā)出。
reduce
- 聚合:用于信號發(fā)出的內(nèi)容是元組,把信號發(fā)出元組的值聚合成一個值。
其中Aggregation(聚合關(guān)系)、Composition(合成關(guān)系)屬于Association(關(guān)聯(lián)關(guān)系),是特殊的Association關(guān)聯(lián)關(guān)系。
可以延伸組合關(guān)系,聚合關(guān)系。
組合關(guān)系:A-B組合成了C C包含所有的A和B
聚合關(guān)系:聚合關(guān)系是整體和個體的關(guān)系(是強(qiáng)的關(guān)聯(lián)關(guān)系) 公司與個人,但是個人不完全屬于公司
- 聚合,常見的用法,(先組合在聚合)。
- combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock
- reduce中的block簡介:
- reduceblcok中的參數(shù),有多少信號組合,reduceblcok就有多少參數(shù),每個參數(shù)就是之前信號發(fā)出的內(nèi)容
- reduceblcok的返回值:聚合信號之后的內(nèi)容。
RACSignal *signalA = [self.tf rac_textSignal];
RACSignal *sigbalB = [self.btn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[RACSignal combineLatest:@[sigbalB, signalA] reduce:^id _Nonnull(id v1, id v2){
return [NSString stringWithFormat:@"reduce = %@-%@", v1, v2];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱到:%@", x);
}];
merge
把多個信號合并成一個信號,任何一個信號發(fā)出,都可以訂閱到。
RACSignal *signalA = [self.tf rac_textSignal];
RACSignal *sigbalB = [self.btn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[signalA merge:sigbalB] subscribeNext:^(id _Nullable x) {
NSLog(@"merge:%@", x);
}];
zip
- 合并信號,任何一個信號發(fā)送數(shù)據(jù),都能監(jiān)聽到。
- 底層實(shí)現(xiàn):
- 定義壓縮信號,內(nèi)部就會自動訂閱signalA,signalB
- 每當(dāng)signalA或者signalB發(fā)出信號,就會判斷signalA,signalB有沒有發(fā)出個信號,有就會把最近發(fā)出的信號都包裝成元組發(fā)出。
RACSignal *signalA = [self.tf rac_textSignal];
RACSignal *sigbalB = [self.btn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[signalA zipWith:sigbalB] subscribeNext:^(id _Nullable x) {
NSLog(@"zip:%@", x);
}];
4. 信號連接
concat
信號相連,依次訂閱到。要注意:前面的信號必須發(fā)送完成,才能接力到下一個信號。
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"one"];
// [subscriber sendError:nil];
// 前面的信號必須發(fā)送完成,才能接力到下一個信號。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalA dispose");
}];
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"two"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalB dispose");
}];
}];
[[signalA concat:signalB] subscribeNext:^(id _Nullable x) {
NSLog(@"concat:%@", x);
}];
then
信號相連,只訂閱到最后一個。要注意:前面的信號必須發(fā)送完成,才能接力到下一個信號。
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"one"];
// [subscriber sendError:nil];
// 前面的信號必須發(fā)送完成,才能接力到下一個信號。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalA dispose");
}];
}] then:^RACSignal * _Nonnull{
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"two"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalB dispose");
}];
}];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"then:%@", x);
}];
5. 信號操作時(shí)間
timeout
NSLog(@"%s", __func__);
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
return [RACDisposable disposableWithBlock:^{
NSLog(@"signal dispose");
}];
}] timeout:5 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id _Nullable x) {
NSLog(@"timeOut:%@", x);
} error:^(NSError * _Nullable error) {
NSLog(@"timeOut-error:%@", error);
}];
輸出:
20:09:29 -[ViewController testTimeOut]
20:09:29 signal dispose
20:09:34 timeOut-error:Error Domain=RACSignalErrorDomain Code=1 "(null)"
interval
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"interval:%@",[NSThread currentThread]);
}];
dely
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signal dispose");
}];
}] delay:3] subscribeNext:^(id _Nullable x) {
NSLog(@"dely:%@", x);
}];
6. 信號取值
take
屏蔽一些信號,取前 N 個信號。
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@2];
[subscriber sendNext:@3];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signal dispose");
}];
}] take:2] subscribeNext:^(id _Nullable x) {
NSLog(@"take:%@", x);
}];
tekeLast
屏蔽一些信號,取后 N 個信號。注意:必須發(fā)送完成信號,才能確定最后的 N 個信號。
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@2];
[subscriber sendNext:@3];
// 必須發(fā)送完成信號,才能確定最后的 N 個信號。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signal dispose");
}];
}] takeLast:2] subscribeNext:^(id _Nullable x) {
NSLog(@"takeLast:%@", x);
}];
takeUntil
[A takeUntil:B]:B發(fā)出信號或者發(fā)出完成信號后,A的信號也就訂閱不到了。
RACSubject *subjectA = [RACSubject subject];
RACSubject *subjectB = [RACSubject subject];
[[subjectA takeUntil:subjectB] subscribeNext:^(id _Nullable x) {
NSLog(@"takeUntil:%@", x);
}];
[subjectA sendNext:@"a-1"];
[subjectA sendNext:@"a-2"];
// [subjectB sendNext:@"b-2"];
[subjectA sendNext:@"a-3"];
[subjectA sendNext:@"a-4"];
[subjectB sendNext:@"b-1"];
[subjectA sendNext:@"a-5"];
7. 信號跳躍
skip
跳過前 N 個信號。
[[self.tf.rac_textSignal skip:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"skip:%@", x);
}];
8. 信號發(fā)送順序
doNext
在源信號發(fā)送之前,可以在doNextBlock中做一些附加操作。
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"signalB-1"];
[subscriber sendNext:@"signalB-2"];
[subscriber sendNext:@"signalB-3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalB dispose");
}];
}];
[[signalB doNext:^(id _Nullable x) {
NSLog(@"do:%@", x);
}] subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱:%@", x);
}];
cocompleted
在源信號發(fā)送完成之前,可以在doCompletedBlock中做一些附加操作。
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"signalB-1"];
[subscriber sendNext:@"signalB-2"];
[subscriber sendCompleted];
[subscriber sendNext:@"signalB-3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalB dispose");
}];
}];
[[signalB doCompleted:^{
NSLog(@"do someting befor completed");
}] subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱到:%@", x);
}];
9. 獲取信號中的信號
switchToLatest
獲取信號中信號最近發(fā)出信號,訂閱最近發(fā)出的信號。
RACSubject *signal = [RACSubject subject];
RACSubject *signalOfSignals = [RACSubject subject];
[[signalOfSignals switchToLatest] subscribeNext:^(id _Nullable x) {
NSLog(@"switchToLatest:%@", x);
}];
// 注意switchToLatest:只能用于信號中的信號
[signalOfSignals sendNext:signal];
[signal sendNext:@"i am a signal"];
10. 信號錯誤重試
retry
發(fā)送失敗就會重新執(zhí)行創(chuàng)建信號時(shí)的block,直至成功發(fā)送。
static int i = 0;
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
if (i == 5) {
[subscriber sendNext:[NSString stringWithFormat:@"%d", i]];
} else {
[subscriber sendError:nil];
}
i++;
return [RACDisposable disposableWithBlock:^{
NSLog(@"signal dispose");
}];
}] retry] subscribeNext:^(id _Nullable x) {
NSLog(@"next:%@", x);
} error:^(NSError * _Nullable error) {
NSLog(@"error:%@", error);
}];
replay
被 N 次訂閱,則發(fā)送 N 遍信號。
RACSignal *signalA = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"signalA-1"];
[subscriber sendNext:@"signalA-2"];
[subscriber sendNext:@"signalA-3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signalA dispose");
}];
}] replay];
[signalA subscribeNext:^(id _Nullable x) {
NSLog(@"replay-1:%@", x);
}];
[signalA subscribeNext:^(id _Nullable x) {
NSLog(@"replay-2:%@", x);
}];