ReactiveCocoa函数响应式编程

ReactiveCocoa简介

由Github 开源的一个应用于iOS和OS X开发的新框架
ReactiveCocoa为事件定义了一个标准接口,iOS 开发中有着各种消息传递机制,包括 KVO、Notification、delegation、block 以及 target-action 方式
本质上RACObserve使用了KVO来监听property的变化,只要username被自己或外部改变,block就会被执行。但不是所有的property都可以被RACObserve,该property必须支持KVO
ReactiveCocoa ,就是用信号接管了iOS 中的所有事件;也就意味着,用一种统一的方式来处理iOS中的所有事件,解决了各种分散的事件处理方式,显然这么一个庞大的框架学习起来也会比较难!而且如果习惯了iOS原生的编程,可能会觉得不习惯!

函数式编程(Functional Programming):使用高阶函数,例如函数用其他函数作为参数。

响应式编程(Reactive Programming):关注于数据流和变化传播。

ReactiveCocoa的使用

KVO

1
2
3
[RACObserve(self, username) subscribeNext:^(id x) {
NSLog(@" 成员变量 username 被修改成了:%@", x);
}];

target-action

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
34
35
36
37
38
39
40
button添加事件
button.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@" 按钮被点击 ");
return [RACSignal empty];
}];
//or
__weak typeof(self) weakSelf = self;
@weakify(self)
[[button rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(id x) {
@strongify(self);
NSLog(@"123444");
}
];
//文本事件监听
@weakify(self);
[[self.nameText rac_textSignal]
subscribeNext:^(id x) {
@strongify(self);
NSLog(@"%@",x);
self.person.name = x;
}];
//组合信号监听
id signals = @[[self.nameText rac_textSignal],[self.passWordText rac_textSignal]];
@weakify(self);
[[RACSignal
combineLatest:signals]
subscribeNext:^(RACTuple *x) {
@strongify(self);
NSString *name = [x first];
NSString *password = [x second];
if (name.length > 0 && password.length > 0) {
self.loginButton.enabled = YES;
self.nameT.name = name;
self.passT.password = password;
} else {
self.loginButton.enabled = NO;
}
}];

Notification

1
2
3
4
5
6
7
[[[NSNotificationCenter defaultCenter]
rac_addObserverForName:@"注册名称"
object:nil]
subscribeNext:^(id x) {
NSLog(@" 键盘 Frame 改变 ");
}
];

Delegate

1
2
3
[[self rac_signalForSelector:@selector(viewWillAppear:)] subscribeNext:^(id x) {
NSLog(@"viewWillAppear 方法被调用 %@", x);
}];

ReactiveCocoa的特点

ReactiveCocoa 优点

传统 iOS 开发过程中,状态以及状态之间依赖过多的问题
传统 MVC 架构的问题:Controller 比较复杂,可测试性差
提供统一的消息传递机制

对于传统的 Model-View-Controller 的框架,Controller 很容易变得比较庞大和复杂。由于 Controller 承担了 Model 和 View 之间的桥梁作用,所以 Controller 常常与对应的 View 和 Model 的耦合度非常高,这同时也造成对其做单元测试非常不容易,对 iOS 工程的单元测试大多都只在一些工具类或与界面无关的逻辑类中进行。

ReactiveCocoa与MVVM关联

RAC 的信号机制很容易将某一个 Model 变量的变化与界面关联,所以非常容易应用 Model-View-ViewModel 框架。通过引入 ViewModel 层,然后用 RAC 将 ViewModel 与 View 关联,View 层的变化可以直接响应 ViewModel 层的变化,这使得 Controller 变得更加简单,由于 View 不再与 Model 绑定,也增加了 View 的可重用性。

ReactiveCocoa 注意

  • 通过 block 函数式 + 链式 的编程,可以让所有相关的代码继承在一起!
  • RAC 在应用中大量使用了 block,由于 Objective-C 语言的内存管理是基于 引用计数 的,为了避免循环引用问题,在 block 中如果要引用 self,需要使用@weakify(self)和@strongify(self)来避免强引用;

@weakify(self); // 定义了一个weak的selfweak变量
@strongify(self); // 局域定义了一个
strong的self指针指向self_weak

1
2
3
4
5
6
7
8
9
10
#define weakify(...) \\
autoreleasepool {} \\
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
#define strongify(...) \\
try {} @finally {} \\
_Pragma("clang diagnostic push") \\
_Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
metamacro_foreach(rac_strongify_,, __VA_ARGS__) \\
_Pragma("clang diagnostic pop")

学习资料

唐巧

袁峥Seemygo