• 开车不需要知道离合器是怎么工作的,但如果知道离合器原理,那么车子可以开得更平稳。
ReactiveCocoa 是一个重型的 FRP 框架,内容十分丰富,它使用了大量内建的 block,这使得其有强大的功能的同时,内部源码也比较复杂。本文研究的版本是2.4.4,小版本间的差别不是太大,无需担心此问题。 这里只探究其核心 RACSignal
源码及其相关部分。本文不会详细解释里面的代码,重点在于讨论那些核心代码是 怎么来
的。文本难免有不正确的地方,请不吝指教,非常感谢。
@protocol RACSubscriber
信号是一个异步数据流,即一个将要发生的以时间为序的事件序列,它能发射出三种不同的东西:value
、error
、completed
。咱们能异步地捕获这些事件:监听信号,针对其发出的三种东西进行操作。“监听”信息的行为叫做 订阅(subscriber)。我们定义的操作就是观察者,这个被“监听”的信号就是被观察的主体(subject) 。其实,这正是“观察者”设计模式!
RAC 针对这个订阅行为定义了一个协议:RACSubscriber。RACSubscriber 协议是与 RACSignal 打交道的唯一方式。咱们先不探究 RACSignal 的内容,而是先研究下 RACSubscriber 是怎么回事。
先来看下 RACSubscriber 的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// 用于从 RACSignal 中直接接收 values 的对象 @protocol RACSubscriber <NSObject> @required /// 发送下一个 value 给 subscribers。value 可以为 nil。 - (void)sendNext:(id)value; /// 发送 error 给 subscribers。 error 可以为 nil。 /// /// 这会终结整个订阅行为,而且接下来也无法再订阅任何信号了。 - (void)sendError:(NSError *)error; /// 发送 completed 给 subscribers。 /// /// 这会终结整个订阅行为,而且接下来也无法再订阅任何信号了。 - (void)sendCompleted; /// 现在重要的是上面三个,先别管这个,忽略掉。 - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable; @end |
##1、NLSubscriber
咱们自己来实现这个协议看看(本文自定义的类都以 “NL” 开头,以视区别):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// NLSubscriber.h @interface NLSubscriber : NSObject <RACSubscriber> @end // NLSubscriber.m @implementation NLSubscriber - (void)sendNext:(id)value { NSLog(@"%s value:%@", sel_getName(_cmd), value); } - (void)sendCompleted { NSLog(@"%s", sel_getName(_cmd)); } - (void)sendError:(NSError *)error { NSLog(@"%s error:%@", sel_getName(_cmd), error); } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable { // to nothing } @end |
现在咱们这个类只关心 sendNext:
、 sendError:
和 sendCompleted
。本类的实现只是简单的打印一些数据。那怎么来使用这个订阅者呢?RACSignal
类提供了接口来让实现了 RACSubscriber
协议的订阅者订阅信号:
1 2 3 4 5 6 7 |
@interface RACSignal (Subscription) /* * `subscriber` 订阅 receiver 的变化。由 receiver 决定怎么给 subscriber 发送事件。 *简单来说,就是由这个被订阅的信号来给订阅者 subscriber 发送 `sendNext:` 等消息。 */ - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber; @end |
用定时器信号来试试看:
1 2 3 4 5 6 7 8 9 10 |
/** * @brief 创建一个定时器信号,每三秒发出一个当时日期值。一共发5次。 */ RACSignal *signalInterval = [RACSignal interval:3.0 onScheduler:[RACScheduler mainThreadScheduler]]; signalInterval = [signalInterval take:5]; NLSubscriber *subscriber = [[NLSubscriber alloc] init]; /** * @brief 用订阅者 subscriber 订阅定时器信号 */ [signalInterval subscribe:subscriber]; |
下面是输出结果:
• 开车不需要知道离合器是怎么工作的,但如果知道离合器原理,那么车子可以开得更平稳。
ReactiveCocoa 是一个重型的 FRP 框架,内容十分丰富,它使用了大量内建的 block,这使得其有强大的功能的同时,内部源码也比较复杂。本文研究的版本是2.4.4,小版本间的差别不是太大,无需担心此问题。 这里只探究其核心 RACSignal
源码及其相关部分。本文不会详细解释里面的代码,重点在于讨论那些核心代码是 怎么来
的。文本难免有不正确的地方,请不吝指教,非常感谢。
@protocol RACSubscriber
信号是一个异步数据流,即一个将要发生的以时间为序的事件序列,它能发射出三种不同的东西:value
、error
、completed
。咱们能异步地捕获这些事件:监听信号,针对其发出的三种东西进行操作。“监听”信息的行为叫做 订阅(subscriber)。我们定义的操作就是观察者,这个被“监听”的信号就是被观察的主体(subject) 。其实,这正是“观察者”设计模式!
RAC 针对这个订阅行为定义了一个协议:RACSubscriber。RACSubscriber 协议是与 RACSignal 打交道的唯一方式。咱们先不探究 RACSignal 的内容,而是先研究下 RACSubscriber 是怎么回事。
先来看下 RACSubscriber 的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// 用于从 RACSignal 中直接接收 values 的对象 @protocol RACSubscriber <NSObject> @required /// 发送下一个 value 给 subscribers。value 可以为 nil。 - (void)sendNext:(id)value; /// 发送 error 给 subscribers。 error 可以为 nil。 /// /// 这会终结整个订阅行为,而且接下来也无法再订阅任何信号了。 - (void)sendError:(NSError *)error; /// 发送 completed 给 subscribers。 /// /// 这会终结整个订阅行为,而且接下来也无法再订阅任何信号了。 - (void)sendCompleted; /// 现在重要的是上面三个,先别管这个,忽略掉。 - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable; @end |
##1、NLSubscriber
咱们自己来实现这个协议看看(本文自定义的类都以 “NL” 开头,以视区别):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// NLSubscriber.h @interface NLSubscriber : NSObject <RACSubscriber> @end // NLSubscriber.m @implementation NLSubscriber - (void)sendNext:(id)value { NSLog(@"%s value:%@", sel_getName(_cmd), value); } - (void)sendCompleted { NSLog(@"%s", sel_getName(_cmd)); } - (void)sendError:(NSError *)error { NSLog(@"%s error:%@", sel_getName(_cmd), error); } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable { // to nothing } @end |
现在咱们这个类只关心 sendNext:
、 sendError:
和 sendCompleted
。本类的实现只是简单的打印一些数据。那怎么来使用这个订阅者呢?RACSignal
类提供了接口来让实现了 RACSubscriber
协议的订阅者订阅信号:
1 2 3 4 5 6 7 |
@interface RACSignal (Subscription) /* * `subscriber` 订阅 receiver 的变化。由 receiver 决定怎么给 subscriber 发送事件。 *简单来说,就是由这个被订阅的信号来给订阅者 subscriber 发送 `sendNext:` 等消息。 */ - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber; @end |
用定时器信号来试试看:
1 2 3 4 5 6 7 8 9 10 |
/** * @brief 创建一个定时器信号,每三秒发出一个当时日期值。一共发5次。 */ RACSignal *signalInterval = [RACSignal interval:3.0 onScheduler:[RACScheduler mainThreadScheduler]]; signalInterval = [signalInterval take:5]; NLSubscriber *subscriber = [[NLSubscriber alloc] init]; /** * @brief 用订阅者 subscriber 订阅定时器信号 */ [signalInterval subscribe:subscriber]; |
下面是输出结果: