本篇博文介绍了 ReactiveCocoa 3.0 (以下简称 RC)全新的 Swift 接口,包括泛型,操作符以及柯里化函数的有趣用法。
这是我为 RC3 系列准备的第一篇文章。这篇文章主要的侧重点是介绍 Swift 版本的 Signal
类,在下一期文章中我会展示一个更完整的应用。
引言
我成为RC的粉丝已经很久了,Ray Wenderlich 网站上已经有我发表的数篇文章,以及一些与 RC 相关的幻灯片。
在Swift问世之初,我们就可以利用桥接 Objective-C 版的 RC 接口在 Swift 中使用 RC。但是能够充分利用 Swift 的特性,如泛型等,会使得 Swift RC 更加纯粹完美!
感谢 RC 团队,他们在过去的几个月里一直工作在全新的 Swift RC 分支上。就在一周前第一个 beta 版本问世,也就是今天这篇文章的主角。
在阅读这篇文章我假定您已经有了一定的 RC 基础,当然,您不用成为一个顶级专家。
创建 SIGNALS
使用 Cathage 可以在项目中非常方便的引入 RC,在工程的根目录创建一个 Cartfile
文件引用 RC3:
1 |
github "ReactiveCocoa/ReactiveCocoa" "v3.0-beta.1" |
如文档所述,运行 carthage update
.
RC3 包含了全新的 Swift API,同时也兼容 Objective-C。所以你会发现两个 Signal 类, Obj-C 版本的 RACSignal
以及 Swift 版本的 Signal
。
Swift 版本的 Signal 类一个重要特性就是它是泛型的:
1 2 3 |
class Signal<T, E: ErrorType> { ... } |
类型参数 T
表明 Signal 对象发出的 ‘next’ 事件所附带的数据类型,错误类型由 E
表示,并要求实现 ErrorType 协议。 Swift 的 signals 类与 OC 版本具有类似的用法,下面展示了一个每秒抛出事件的 signal 类:
1 2 3 4 5 6 7 8 9 10 |
func createSignal() -> Signal<String, NoError> { var count = 0 return Signal { sink in NSTimer.schedule(repeatInterval: 1.0) { timer in sendNext(sink, "tick #(count++)") } return nil } } |
Signal
类的初始化方法需要传入一个生成器,在上例中传入的是一个闭包。生成器被调用后传入一个 sink 对象,sink 对象的类型是 SinkOf<Event<String, NoError>>
。任何发送给 sink 对象的事件都会被 signal 对象抛出。
sendNext
函数把局部变量 count 作为第二个参数,构造了一个事件传递给 sink。
Swift Signal 类与 ObjC 版本的 Signal 类有相似的内存管理机制,当一个 signal 实例生命周期结束时,需要被释放。在上例中这一步被包含在闭包表达式之中的最后一步
监听 SIGNALS
有若干种方法你可以监听一个 Signal。最简单的方法是使用 observe
方法,为你所感兴趣的事件提供一个函数或者闭包回调。
这是一个监听 next 事件的例子:
1 2 |
let signal = createSignal() signal.observe(next: { println($0) }) |
输出如下:
1 2 3 4 5 |
tick #0 tick #1 tick #2 tick #3 tick #4 |
或者,你可以提供一个 sink 变量监听 signal 的时间:
1 2 3 4 5 6 7 8 9 |
createSignal().observe(SinkOf { event in switch event { case let .Next(data): println(data.unbox) default: break } }) |
Event 类型是一个枚举,关联了 next 和 error 事件。Sinkof 初始化方法构造了一个 SinkOf<Event<String, NoError>> 类型的sink 变量,同样的,后面的闭包表达式作为参数传给了初始化方法。
由于 Swift 语言的限制,Event 类型的枚举(next,error 事件)携带的数据被 LlamaKit Box 类封装在暗盒中,作为一个 RC3 的使用者你很少需要直接跟 Event 类型打交道,有很多 API 可以帮你进行封装和解封的操作。
上面的例子展示了些许 Swift 跟 RC 结合所带来的优势。使用泛型定义 Signal 意味着监听事件时可以更安全的获取数据类型,此外,如果你使用的是很复杂的泛型嵌套,你也不用去显式的声明泛型了。
转换 SIGNALS
Swift Signal 类型与它的 Objc 版本具有诸多相似的特性.可是,他们之间有一个根本的区别。
对于一个简单的map操作,你通常会定义一个Signal的方法,伪代码如下:
1 2 3 |
class Signal<T, E: ErrorType> { func map(transform: ...) -> Signal } |
不过,map 函数以及其他能应用于 Signal 的操作实际上都是非成员函数:
这是我为 RC3 系列准备的第一篇文章。这篇文章主要的侧重点是介绍 Swift 版本的 Signal
类,在下一期文章中我会展示一个更完整的应用。
引言
我成为RC的粉丝已经很久了,Ray Wenderlich 网站上已经有我发表的数篇文章,以及一些与 RC 相关的幻灯片。
在Swift问世之初,我们就可以利用桥接 Objective-C 版的 RC 接口在 Swift 中使用 RC。但是能够充分利用 Swift 的特性,如泛型等,会使得 Swift RC 更加纯粹完美!
感谢 RC 团队,他们在过去的几个月里一直工作在全新的 Swift RC 分支上。就在一周前第一个 beta 版本问世,也就是今天这篇文章的主角。
在阅读这篇文章我假定您已经有了一定的 RC 基础,当然,您不用成为一个顶级专家。
创建 SIGNALS
使用 Cathage 可以在项目中非常方便的引入 RC,在工程的根目录创建一个 Cartfile
文件引用 RC3:
1 |
github "ReactiveCocoa/ReactiveCocoa" "v3.0-beta.1" |
如文档所述,运行 carthage update
.
RC3 包含了全新的 Swift API,同时也兼容 Objective-C。所以你会发现两个 Signal 类, Obj-C 版本的 RACSignal
以及 Swift 版本的 Signal
。
Swift 版本的 Signal 类一个重要特性就是它是泛型的:
1 2 3 |
class Signal<T, E: ErrorType> { ... } |
类型参数 T
表明 Signal 对象发出的 ‘next’ 事件所附带的数据类型,错误类型由 E
表示,并要求实现 ErrorType 协议。 Swift 的 signals 类与 OC 版本具有类似的用法,下面展示了一个每秒抛出事件的 signal 类:
1 2 3 4 5 6 7 8 9 10 |
func createSignal() -> Signal<String, NoError> { var count = 0 return Signal { sink in NSTimer.schedule(repeatInterval: 1.0) { timer in sendNext(sink, "tick #(count++)") } return nil } } |
Signal
类的初始化方法需要传入一个生成器,在上例中传入的是一个闭包。生成器被调用后传入一个 sink 对象,sink 对象的类型是 SinkOf<Event<String, NoError>>
。任何发送给 sink 对象的事件都会被 signal 对象抛出。
sendNext
函数把局部变量 count 作为第二个参数,构造了一个事件传递给 sink。
Swift Signal 类与 ObjC 版本的 Signal 类有相似的内存管理机制,当一个 signal 实例生命周期结束时,需要被释放。在上例中这一步被包含在闭包表达式之中的最后一步
监听 SIGNALS
有若干种方法你可以监听一个 Signal。最简单的方法是使用 observe
方法,为你所感兴趣的事件提供一个函数或者闭包回调。
这是一个监听 next 事件的例子:
1 2 |
let signal = createSignal() signal.observe(next: { println($0) }) |
输出如下:
1 2 3 4 5 |
tick #0 tick #1 tick #2 tick #3 tick #4 |
或者,你可以提供一个 sink 变量监听 signal 的时间:
1 2 3 4 5 6 7 8 9 |
createSignal().observe(SinkOf { event in switch event { case let .Next(data): println(data.unbox) default: break } }) |
Event 类型是一个枚举,关联了 next 和 error 事件。Sinkof 初始化方法构造了一个 SinkOf<Event<String, NoError>> 类型的sink 变量,同样的,后面的闭包表达式作为参数传给了初始化方法。
由于 Swift 语言的限制,Event 类型的枚举(next,error 事件)携带的数据被 LlamaKit Box 类封装在暗盒中,作为一个 RC3 的使用者你很少需要直接跟 Event 类型打交道,有很多 API 可以帮你进行封装和解封的操作。
上面的例子展示了些许 Swift 跟 RC 结合所带来的优势。使用泛型定义 Signal 意味着监听事件时可以更安全的获取数据类型,此外,如果你使用的是很复杂的泛型嵌套,你也不用去显式的声明泛型了。
转换 SIGNALS
Swift Signal 类型与它的 Objc 版本具有诸多相似的特性.可是,他们之间有一个根本的区别。
对于一个简单的map操作,你通常会定义一个Signal的方法,伪代码如下:
1 2 3 |
class Signal<T, E: ErrorType> { func map(transform: ...) -> Signal } |
不过,map 函数以及其他能应用于 Signal 的操作实际上都是非成员函数: