OC三方框架07:ReactiveCocoa使用

张建 lol

前言

RAC 全称 ReactiveCocoa,是一个重量级的三方框架,接管了苹果的所有事件机制,RAC主要是 监听事件,并能 立即作为响应,即 响应式编程

RAC 大纲

RAC信号三部曲

  • 创建信号
1
2
3
4
// 创建信号
RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
return nil;
}];

注:
在创建信号中有个block参数 subscriber(订阅者),只有在接收到订阅信号时,才能发送信号

  • 订阅信号
1
2
3
4
// 订阅信号
[signal subscribeNext:^(id _Nullable x) {
ZJLog(@"x:%@",x);
}];

注:
订阅信号通过block接收发送信号的内容

  • 发送信号
1
2
// 发送信号
[subscriber sendNext:@"test"];

注:
发送信号,要放在创建信号的block中

  • 合并写法
1
2
3
4
5
6
7
8
9
// 创建信号
[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 发送信号
[subscriber sendNext:@"This is RAC"];
return nil;
}] subscribeNext:^(id _Nullable x) {
// 订阅信号
NSLog(@"x:%@",x);
}];

RAC的使用

  • UIButton
1
2
3
[[self.dynamicBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"x:%@",x);
}];
  • 监听单个 UITextField
1
2
3
4
// 监听密码改变的状态
[[self.pwdTF rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
[weakSelf handlePwdChangeAction:x];
}];
  • 监听多个 UITextField
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[[RACSignal combineLatest:@[self.oldpwdTF.rac_textSignal,
self.newpwdTF.rac_textSignal,
self.surepwdTF.rac_textSignal]
reduce:^id _Nonnull(NSString * oldpwd,NSString * newpwd,NSString * surepwd){
// NSLog(@"%@--%@--%@",oldpwd,newpwd,surepwd);
// 返回
return @(oldpwd.length >= 6 && newpwd.length >= 6 && surepwd.length >= 6);
}] subscribeNext:^(id _Nullable x) {
// ZJLog(@"%@",x);
// 是否能够点击
BOOL isEnabled = [x boolValue];
weakSelf.finishBtn.enabled = isEnabled;
if (isEnabled) {
weakSelf.finishBtn.backgroundColor = kColorHexStrA(@"#3161F3", 1.0);
}else {
weakSelf.finishBtn.backgroundColor = kColorHexStrA(@"#3161F3", 0.3);
}
}];
  • 通知(不需要手动remove)
1
2
3
4
// 监听将要进入前台
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationWillEnterForegroundNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
ZJLog(@"将要进入前台");
}];
  • KVO 监听属性变化
1
2
3
4
5
6
7
8
9
10
@property(noatomic,assign) int age; 

[[self rac_valueForKeyPath:@"age" observer:nil] subscribeNext:^(id x ){
NSLog(@"%@",x);
}];

// 模拟一个事件 触摸屏幕 就让age自增
-(void)touchesBegin:(NSSet<UITouch*>*)touches WithEvent:(UIEvent*)event{
age++;
}
  • KVO 快速监听某个 对象 的某个属性变化
1
2
3
4
// 监听当前视图控制器 中心圆点的变化
[RACObserve(self.view, center) subscribeNext:^(id _Nullable x) {
NSLog(@"x:%@",x);
}];

RAC实现读个网络请求都完成后再刷新界面

使用方法 - (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals 当传入的 signals(信号数组),每一个 signal 都至少 sendNext 过一次,才会去触发第一个 selector 参数的方法,就是说放 signals 中的所有请求信号都执行完成后才会触发 selector 对应的方法

应用示例:

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
31
32
33
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"请求第一项数据");
[subscriber sendNext:@"获取到第一项数据"];
return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"请求第二项数据");
[subscriber sendNext:@"获取到第二项数据"];
return nil;
}];
RACSignal * signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"请求第三项数据");
[subscriber sendNext:@"获取到第三项数据"];
return nil;
}];

/*
Selector 调用:当所有信号都发送数据时调用
数组存放多个信号
Selector 注意点:参数根据数组元素决定(数据的顺序/数据类型)
Selector 方法中的参数类型,就是信号传递出来的数据
*/
[self rac_liftSelector:@selector(updateUIWithData1:data2:data3:) withSignalsFromArray:@[signal1,signal2,signal3]];
}

- (void)updateUIWithData1:(NSString *)data1 data2:(NSString *)data2 data3:(NSString *)data3{
// 输出 data1:获取到第一项数据 data2:获取到第三项数据 data3:获取到第二项数据
NSLog(@"data1:%@ data2:%@ data3:%@",data1,data2,data3);
}

concat (网络请求的顺序执行)

  • 按照一定的顺序执行

  • 如果我们处理网络请求时,遇到先执行一个网络请求得到结果后,再去执行另一个网络请求

  • 相当于必须先执行完 信号A,才会执行 信号B,这时就会用到 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
RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
NSLog(@"请求A数据");
[subscriber sendNext:@"A"];
// 发送信号完成,表示不再订阅了,内部会自动调用[RACDisposable disposable]取消订阅信号。
[subscriber sendCompleted];
return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"请求B数据");
[subscriber sendNext:@"B"];
[subscriber sendCompleted];
return nil;
}];
RACSignal * signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"请求C数据");
[subscriber sendNext:@"C"];
[subscriber sendCompleted];
return nil;
}];
// 按顺序执行信号
RACSignal * concatSignal = [RACSignal concat:@[signal1,signal2,signal3]];
[concatSignal subscribeNext:^(id _Nullable x) {
// 分别输出A,B,C
NSLog(@"%@",x);
}];

查看打印结果:

1
2
3
4
5
6
2023-07-15 16:29:01.411929+0800 DigitalGuard[11168:862724] 请求A数据
2023-07-15 16:29:05.033538+0800 DigitalGuard[11168:862724] A
2023-07-15 16:29:05.035488+0800 DigitalGuard[11168:862724] 请求B数据
2023-07-15 16:29:08.084930+0800 DigitalGuard[11168:862724] B
2023-07-15 16:29:08.085394+0800 DigitalGuard[11168:862724] 请求C数据
2023-07-15 16:29:09.900995+0800 DigitalGuard[11168:862724] C

merge 合并信号

  • 把多个信号合并为一个信号,任何一个信号有新值的时候就会调用,没有顺序

  • 哪个先发送 就先执行哪个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
[subscriber sendNext:@"1"];
return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"2"];
return nil;
}];
RACSignal * signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"3"];
return nil;
}];

RACSignal * mergeSignal = [RACSignal merge:@[signal3,signal1,signal2]];
[mergeSignal subscribeNext:^(id _Nullable x) {
// 分别输出3,1,2
NSLog(@"x:%@",x);
}];

then

  • 用于连接两个信号,内部也是使用concat,当前一个信号完成之后才会连接then返回的信号,

  • 会忽略前一个信号,只会触发下个信号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
[subscriber sendNext:@(1)];
[subscriber sendCompleted];
return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@(2)];
[subscriber sendCompleted];
return nil;
}];
RACSignal * thenSignal = [signal1 then:^RACSignal * _Nonnull{
return signal2;
}];
[thenSignal subscribeNext:^(id _Nullable x) {
// 输出2
NSLog(@"%@",x);
}];

zip

  • 把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组

  • 打印顺序跟组合顺序,跟发送的顺序无关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
[subscriber sendNext:@(1)];
// 不会覆盖上一个信号
[subscriber sendNext:@(3)];
return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@(2)];
return nil;
}] ;
RACSignal *zipSignal = [RACSignal zip:@[signal1,signal2]];
[zipSignal subscribeNext:^(id _Nullable x) {
// 输出(1,2)
NSLog(@"%@",x);
}];

常用宏

  • RAC(TARGET,…) : 给某个对象的某个属性进行绑定
1
2
// 当textfield开始编辑时,关闭button响应
RAC(_button,enabled) = [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] mapReplace:@NO];
  • RACObserve(TARGET, KEYPATH):KVO,监听某个对象的属性,返回的是信号
1
2
3
4
[RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
// 新背景颜色
NSLog(@"%@",x);
}];
  • RACChannelTo:用于双向绑定的一个通道终端
1
2
// 将 button.backgroundColor 跟 view.backgroundColor 绑定
RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);

combineLatest

  • 当组合信号被订阅,内部会自动订阅signalA,signalB,必须两个信号都发出内容,才会被触发。

  • 并且把两个信号组合成元组发出。

1
2
3
4
5
6
7
8
9
// 创建信号A
RACSubject * signalA = [RACSubject subject];
// 创建信号B
RACSubject * signalB = [RACSubject subject];
[[RACSignal combineLatest:@[signalA,signalB]]subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"%@",x);
}];
[signalA sendNext:@"A"];
[signalB sendNext:@"B"];

reduce聚合

  • 把信号发出元组的值聚合成一个值,可以把数据处理完成返回一个新的值
1
2
3
4
5
6
7
8
9
10
11
12
13
// 创建信号A
RACSubject * signalA = [RACSubject subject];
// 创建信号B
RACSubject * signalB = [RACSubject subject];
[[RACSignal combineLatest:@[signalA,signalB] reduce:^id _Nullable(NSString *username,NSString *pwd){
// 处理数据
return [NSString stringWithFormat:@"reduce--%@--%@",username,pwd];
}]subscribeNext:^(id _Nullable x) {
// 输出 reduce--A--B
NSLog(@"reduce--%@",x);
}];
[signalA sendNext:@"A"];
[signalB sendNext:@"B"];
  • Post title:OC三方框架07:ReactiveCocoa使用
  • Post author:张建
  • Create time:2023-07-15 14:31:51
  • Post link:https://redefine.ohevan.com/2023/07/15/OC三方框架/OC三方框架07:ReactiveCocoa使用/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.