ReactiveCocoa入门教程(上)

609 查看

作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback等。ReactiveCocoa为事件定义了一个标准接口,从而可以使用一些基本工具来更容易的连接、过滤和组合。

 

如果你对上面说的还比较疑惑,那还是继续往下看吧。

 

ReactiveCocoa结合了几种编程风格:

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

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

 

所以,你可能听说过ReactiveCocoa被描述为函数响应式编程(FRP)框架。

 

这就是这篇教程要讲的内容。编程范式是个不错的主题,但是本篇教程的其余部分将会通过一个例子来实践。

Reactive Playground

通过这篇教程,一个简单的范例应用Reactive Playground ,你将会了解到响应式编程。下载初始工程,然后编译运行一下确保你已经把一切都设置正确了。

 

Reactive Playground是一个非常简单的应用,它为用户展示了一个登录页。在用户名框输入user,在密码框输入password,然后你就能看到有一只可爱小猫咪的欢迎页了。

ReactivePlaygroundStarter-1

呀,真是可爱啊。

 

现在可以花一些时间来看一下初始工程的代码。很简单,用不了多少时间。

 

打开RWViewController.m看一下。你多快能找到控制登录按钮是否可用的条件?判断显示/隐藏登录失败label的条件是什么?在这个相对简单的例子里,可能只用一两分钟就能回答这些问题。但是对于更复杂的例子,这些所花的时间可能就比较多了。

 

使用ReactiveCocoa,可以使应用的基本逻辑变得相当简洁。是时候开始啦。

添加ReactiveCocoa框架

添加ReactiveCocoa框架最简单的方法就是用CocoaPods。如果你从没用过CocoaPods,那还是先去看看CocoaPods简介这篇教程吧。请至少看完教程中初始化的步骤,这样你才能安装框架。

 

注意:如果不想用CocoaPods,你仍然可以使用ReactiveCocoa,具体查看Github文档中引入ReactiveCocoa的步骤描述。

译注:我就是不喜欢用CocoaPods的那波人。所以我首先使用了Github上提供的方法,但是在第二步执行bootstrap时提示缺少xctool,我就果断放弃了,还是乖乖用CocoaPods吧。

 

具体怎么使用CocoaPods安装就不详细讲解了。

开动

就像在介绍中提到的,RAC为应用中发生的不同事件流提供了一个标准接口。在ReactiveCocoa术语中这个叫做信号(signal),由RACSignal类表示。

 

打开应用的初始view controller,RWViewController.m ,引入ReactiveCocoa的头文件。

不要替换已有的代码,将下面的代码添加到viewDidLoad方法的最后:

编译运行,在用户名输入框中输几个字。注意console的输出应该和下面的类似。

 

可以看到每次改变文本框中的文字,block中的代码都会执行。没有target-action,没有delegate,只有signal和block。令人激动不是吗?

 

ReactiveCocoa signal(RACSignal)发送事件流给它的subscriber。目前总共有三种类型的事件:nexterrorcompleted。一个signal在因error终止或者完成前,可以发送任意数量的next事件。在本教程的第一部分,我们将会关注next事件。在第二部分,将会学习error和completed事件。

 

RACSignal有很多方法可以来订阅不同的事件类型。每个方法都需要至少一个block,当事件发生时就会执行block中的逻辑。在上面的例子中可以看到每次next事件发生时,subscribeNext:方法提供的block都会执行。

 

ReactiveCocoa框架使用category来为很多基本UIKit控件添加signal。这样你就能给控件添加订阅了,text field的rac_textSignal就是这么来的。

 

 

原理就说这么多,是时候开始让ReactiveCocoa干活了。

 

ReactiveCocoa有很多操作来控制事件流。假设你只关心超过3个字符长度的用户名,那么你可以使用filter操作来实现这个目的。把之前加在viewDidLoad中的代码更新成下面的:

编译运行,在text field只能怪输入几个字,你会发现只有当输入超过3个字符时才会有log。