RAC高階函數(shù)

RAC高階函數(shù)

0. bind

  • bind方法使用步驟:
    1. 傳入一個返回值RACStreamBindBlock的block。
    2. 描述一個RACStreamBindBlock類型的bindBlock作為block的返回值。
    3. 描述一個返回結(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底層原理
    1. 源信號調(diào)用bind,會重新創(chuàng)建一個綁定信號。
    2. 當(dāng)綁定信號被訂閱,就會調(diào)用綁定信號中的didSubscribe,生成一個bindingBlock。
    3. 當(dāng)源信號有內(nèi)容發(fā)出,就會把內(nèi)容傳遞到bindingBlock處理,調(diào)用bindingBlock(value,stop)
    4. 調(diào)用bindingBlock(value,stop),會返回一個內(nèi)容處理完成的信號(RACReturnSignal)。
    5. 訂閱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):
    1. flattenMap內(nèi)部調(diào)用bind方法實(shí)現(xiàn)的,flattenMap中block的返回值,會作為bind中bindBlock的返回值。
    2. 當(dāng)訂閱綁定信號,就會生成bindBlock。
    3. 當(dāng)源信號發(fā)送內(nèi)容,就會調(diào)用bindBlock(value, *stop)
    4. 調(diào)用bindBlock,內(nèi)部就會調(diào)用flattenMap的block,flattenMap的block作用:就是把處理好的數(shù)據(jù)包裝成信號。
    5. 返回的信號最終會作為bindBlock中的返回信號。
    6. 訂閱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):
    1. 當(dāng)組合信號被訂閱,內(nèi)部會自動訂閱signalA,signalB,必須兩個信號都發(fā)出內(nèi)容,才會被觸發(fā)。
    2. 并且把兩個信號組合成元組發(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):
    1. 定義壓縮信號,內(nèi)部就會自動訂閱signalA,signalB
    2. 每當(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);
}];
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容