ReactiveCocoa 操作之信号处理

ReactiveCocoa 操作之信号处理

1,映射(flattenMap,Map)

  • flattenMap,Map用于把源信号内容映射成新的内容
  • flattenMap作用:把源信号的内容映射成一个新的信号,信号可以是任意类型。
1
2
3
4
5
6
7
8
9
10
11
[[_textField.rac_textSignal flattenMap:^RACStream *(id value) {
// block什么时候 : 源信号发出的时候,就会调用这个block。
// block作用 : 改变源信号的内容。
// 返回值:绑定信号的内容.
return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]];
}] subscribeNext:^(id x) {
// 订阅绑定信号,每当源信号发送内容,做完处理,就会调用这个block。
NSLog(@"%@",x);
}];
  • Map作用:把源信号的值映射成一个新的值
1
2
3
4
5
6
7
8
[[_textField.rac_textSignal map:^id(id value) {
// 当源信号发出,就会调用这个block,修改源信号的内容
// 返回值:就是处理完源信号的内容。
return [NSString stringWithFormat:@"输出:%@",value];
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
  • FlatternMap和Map的区别

    1.FlatternMap中的Block返回信号。

    2.Map中的Block返回对象。

    3.开发中,如果信号发出的值不是信号,映射一般使用Map

    4.开发中,如果信号发出的值是信号,映射一般使用FlatternMap

    2,组合

  • 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
25
26
27
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
// 把signalA拼接到signalB后,signalA发送完成,signalB才会被激活。
RACSignal *concatSignal = [signalA concat:signalB];
// 以后只需要面对拼接信号开发。
// 订阅拼接的信号,不需要单独订阅signalA,signalB
// 内部会自动订阅。
// 注意:第一个信号必须发送完成,第二个信号才会被激活
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
  • then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号
// 注意使用then,之前信号的值会被忽略掉.
// 底层实现:1、先过滤掉之前的信号发出的值。2.使用concat连接then返回的信号
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
}] subscribeNext:^(id x) {
// 只能接收到第二个信号的值,也就是then返回信号的值
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
    25
    // merge:把多个信号合并成一个信号
    //创建多个信号
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@1];
    return nil;
    }];
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@2];
    return nil;
    }];
    // 合并信号,任何一个信号发送数据,都能监听到.
    RACSignal *mergeSignal = [signalA merge:signalB];
    [mergeSignal subscribeNext:^(id x) {
    NSLog(@"%@",x);
    }];
  • zipWith:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件。

    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 *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@1];
    return nil;
    }];
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@2];
    return nil;
    }];
    // 压缩信号A,信号B
    RACSignal *zipSignal = [signalA zipWith:signalB];
    [zipSignal subscribeNext:^(id x) {
    NSLog(@"%@",x);
    }];
  • combineLatest:将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@1];
    return nil;
    }];
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@2];
    return nil;
    }];
    // 把两个信号组合成一个信号,跟zip一样,没什么区别
    RACSignal *combineSignal = [signalA combineLatestWith:signalB];
    [combineSignal subscribeNext:^(id x) {
    NSLog(@"%@",x);
    }];
  • reduce聚合:用于信号发出的内容是元组,把信号发出元组的值聚合成一个值
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
30
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
// 聚合
// 常见的用法,(先组合在聚合)。combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock
// reduce中的block简介:
// reduceblcok中的参数,有多少信号组合,reduceblcok就有多少参数,每个参数就是之前信号发出的内容
// reduceblcok的返回值:聚合信号之后的内容。
RACSignal *reduceSignal = [RACSignal combineLatest:@[signalA,signalB] reduce:^id(NSNumber *num1 ,NSNumber *num2){
return [NSString stringWithFormat:@"%@ %@",num1,num2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

3,过滤

  • filter:过滤信号,使用它可以获取满足条件的信号
1
2
3
4
5
// 过滤:
// 每次信号发出,会先执行过滤条件判断.
[_textField.rac_textSignal filter:^BOOL(NSString *value) {
return value.length > 3;
}];
  • ignore:忽略完某些值的信号
1
2
3
4
5
// 内部调用filter过滤,忽略掉ignore的值
[[_textField.rac_textSignal ignore:@"1"] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
  • distinctUntilChanged:当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。
1
2
3
4
5
6
// 过滤,当上一次和当前的值不一样,就会发出内容。
// 在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
[[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
  • take:从开始一共取N次的信号
1
2
3
4
5
6
7
8
9
10
11
12
13
// 1、创建信号
RACSubject *signal = [RACSubject subject];
// 2、处理信号,订阅信号
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.发送信号
[signal sendNext:@1];
[signal sendNext:@2];
  • takeLast:取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1、创建信号
RACSubject *signal = [RACSubject subject];
// 2、处理信号,订阅信号
[[signal takeLast:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.发送信号
[signal sendNext:@1];
[signal sendNext:@2];
[signal sendCompleted];
  • takeUntil:(RACSignal *):获取信号直到某个信号执行完成
1
2
// 监听文本框的改变直到当前对象被销毁
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
  • skip:(NSUInteger):跳过几个信号,不接受
1
2
3
4
5
// 表示输入第一次,不会被监听到,跳过第一次发出的信号
[[_textField.rac_textSignal skip:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
  • switchToLatest:用于signalOfSignals(信号的信号),有时候信号也会发出信号,会在signalOfSignals中,获取signalOfSignals发送的最新信号。
1
2
3
4
5
6
7
8
9
10
11
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
// 获取信号中信号最近发出信号,订阅最近发出的信号。
// 注意switchToLatest:只能用于信号中的信号
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signalOfSignals sendNext:signal];
[signal sendNext:@1];

3,秩序

  • doNext: 执行Next之前,会先执行这个Block
  • doCompleted: 执行sendCompleted之前,会先执行这个Block
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] doNext:^(id x) {
// 执行[subscriber sendNext:@1];之前会调用这个Block
NSLog(@"doNext");;
}] doCompleted:^{
// 执行[subscriber sendCompleted];之前会调用这个Block
NSLog(@"doCompleted");;
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

4,线程

  • deliverOn: 内容传递切换到制定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。
  • subscribeOn: 内容传递和副作用都会切换到制定线程中

5,时间

  • timeout: 超时,可以让一个信号在一定的时间后,自动报错。
1
2
3
4
5
6
7
8
9
10
11
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
return nil;
}] timeout:1 onScheduler:[RACScheduler currentScheduler]];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
// 1秒后会自动调用
NSLog(@"%@",error);
}];
  • interval: 定时:每隔一段时间发出信号
1
2
3
4
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
  • delay 延迟发送next
1
2
3
4
5
6
7
8
RACSignal *signal = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

6,重复

  • retry:重试 :只要失败,就会重新执行创建信号中的block,直到成功.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (i == 10) {
[subscriber sendNext:@1];
}else{
NSLog(@"接收到错误");
[subscriber sendError:nil];
}
i++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
}];
  • replay :重放:当一个信号被多次订阅,反复播放内容
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
RACSignal signal = [[RACSignal createSignal:^RACDisposable (id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一个订阅者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二个订阅者%@",x);
}];
//// console log:
2015-10-26 16:15:31.865 RACDemo[96570:826207] 第一个订阅者1
2015-10-26 16:15:31.866 RACDemo[96570:826207] 第一个订阅者2
2015-10-26 16:15:31.866 RACDemo[96570:826207] 第二个订阅者1
2015-10-26 16:15:31.867 RACDemo[96570:826207] 第二个订阅者2
  • throttle节流:当某个信号发送比较频繁时,可以使用节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出。
1
2
3
4
5
6
7
8
9
RACSubject *signal = [RACSubject subject];
_signal = signal;
// 节流,在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出。
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

下一期: MVVM思想