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,需要手動導入頭文件RACReturnSignal.h。
- bind底層原理
- 源信號調(diào)用bind,會重新創(chuàng)建一個綁定信號按灶。
- 當綁定信號被訂閱症革,就會調(diào)用綁定信號中的didSubscribe,生成一個bindingBlock鸯旁。
- 當源信號有內(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ù)的手機號,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):
- flattenMap內(nèi)部調(diào)用bind方法實現(xiàn)的,flattenMap中block的返回值,會作為bind中bindBlock的返回值瓦灶。
- 當訂閱綁定信號鸠删,就會生成bindBlock。
- 當源信號發(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
- 當上一次的值和當前的值有明顯的變化就會發(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):
- 當組合信號被訂閱,內(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)系(是強的關(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):
- 定義壓縮信號,內(nèi)部就會自動訂閱signalA曹步,signalB
- 每當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);
}];