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,需要手動導入頭文件RACReturnSignal.h。

  • bind底層原理
    1. 源信號調(diào)用bind,會重新創(chuàng)建一個綁定信號按灶。
    2. 當綁定信號被訂閱症革,就會調(diào)用綁定信號中的didSubscribe,生成一個bindingBlock鸯旁。
    3. 當源信號有內(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ù)的手機號,map中在前面添加+86辞居,超過11位時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底層實現(xiàn):
    1. flattenMap內(nèi)部調(diào)用bind方法實現(xiàn)的,flattenMap中block的返回值,會作為bind中bindBlock的返回值瓦灶。
    2. 當訂閱綁定信號鸠删,就會生成bindBlock。
    3. 當源信號發(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

  • 當上一次的值和當前的值有明顯的變化就會發(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);
}];
  • 底層實現(xiàn):
    1. 當組合信號被訂閱,內(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)系(是強的關(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)聽到俱两。
  • 底層實現(xiàn):
    1. 定義壓縮信號,內(nèi)部就會自動訂閱signalA曹步,signalB
    2. 每當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. 信號操作時間

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)建信號時的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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饭弓,隨后出現(xiàn)的幾起案子双饥,更是在濱河造成了極大的恐慌,老刑警劉巖弟断,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咏花,死亡現(xiàn)場離奇詭異,居然都是意外死亡阀趴,警方通過查閱死者的電腦和手機昏翰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刘急,“玉大人棚菊,你說我怎么就攤上這事∈逯” “怎么了统求?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長据块。 經(jīng)常有香客問我码邻,道長,這世上最難降的妖魔是什么另假? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任像屋,我火速辦了婚禮,結(jié)果婚禮上边篮,老公的妹妹穿的比我還像新娘己莺。我一直安慰自己,他們只是感情好苟耻,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布篇恒。 她就那樣靜靜地躺著,像睡著了一般凶杖。 火紅的嫁衣襯著肌膚如雪胁艰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音腾么,去河邊找鬼奈梳。 笑死,一個胖子當著我的面吹牛解虱,可吹牛的內(nèi)容都是我干的攘须。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼殴泰,長吁一口氣:“原來是場噩夢啊……” “哼于宙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悍汛,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤捞魁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后离咐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谱俭,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年宵蛀,在試婚紗的時候發(fā)現(xiàn)自己被綠了昆著。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡术陶,死狀恐怖凑懂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞳别,我是刑警寧澤征候,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站祟敛,受9級特大地震影響疤坝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜馆铁,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一跑揉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧埠巨,春花似錦历谍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勋桶,卻和暖如春脱衙,著一層夾襖步出監(jiān)牢的瞬間侥猬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工捐韩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留退唠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓荤胁,卻偏偏與公主長得像瞧预,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仅政,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356