在我的前一篇博客中首次尝试了ReactiveCocoa3.0 (RC3),在那篇博客中提到了新的 Signal 接口和 |> 操作符。 在这篇博客中我将继续我们探索RC3 API的旅程,我将着重讲述信号发生器,还会从整体上谈论一下新 ReactiveCocoa API 的易用性。
如果你已经使用过 ReactiveCocoa,那么你或许已经遇到过热信号和冷信号的概念区分问题,由于这两个概念都是通过同样的 RACSignal 类型表现出来的,所以区分这两个概念一直以来都是个问题。ReactiveCocoa的设计指导文档建议采用不同的命名方式来区分他们,但是这仍然很难以捉摸。
在RC3中使用不同的类型(信号和信号发生器)来代表他们,让热信号和冷信号之间的区别变得更加明显,也让有着细微区别的操作符命名法变得不再细微(你观察一个信号,但是启动一个信号发生者)。在RC3中令人困惑的热信号和冷信号已经彻底消失了。
信号
比较 Signal 和 SignalProducer 最好的方法就是尝试使用它们。
在我的上一篇博客中,我创建了一个简单的信号,它可以每秒发送一个 next 事件:
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 } } |
通过添加几个 println 语句,我们可以观察到什么时候构建信号什么时候发送 next 事件。
1 2 3 4 5 6 7 8 9 10 11 12 |
func createSignal() -> Signal<String, NoError> { var count = 0 return Signal { sink in println("Creating the timer signal") NSTimer.schedule(repeatInterval: 0.1) { timer in println("Emitting a next event") sendNext(sink, "tick #(count++)") } return nil } } |
如果你创建一个信号的实例:
1 |
let signal = createSignal() |
但是不添加任何一个观察者,由于没有观察者,你将只能看到信号的创建和事件的发送。
1 2 3 4 5 |
Creating the timer signal Emitting a next event Emitting a next event Emitting a next event ... |
信号发生器
信号发生器的初始化使用了同样的模式:
1 2 3 4 5 6 7 8 9 10 11 |
func createSignalProducer() -> SignalProducer<String, NoError> { var count = 0 return SignalProducer { sink, disposable in println("Creating the timer signal producer") NSTimer.schedule(repeatInterval: 0.1) { timer in println("Emitting a next event") sendNext(sink, "tick #(count++)") } } } |
信号和信号发生器在初始化时候的区别不太明显,信号发生器和信号采用同样的范型类型作为参数,一个为next事件的类型,另一个为错误类型。它们也都很典型地在初始化的时候使用了闭包表达式,不过这个闭包表达式并不是返回一个容器变量 RACDisposable ,而是用一个复合的容器实例作为参数。
如果你创建了一个信号发生器,但是没有订阅(没有添加观察者):
1 |
let signalProducer = createSignalProducer() |
你会发现没有 log 被显示在控制台窗口上,定时器也没有启动。
信号发生器是在启动时产生信号的工厂。为了启动定时器,你可以调用定义在信号发生器中的 start 方法或者和 signal API 一样,通过 |> 操作符来使用 start 函数。