ReactiveCocoa源码拆分解析(六)

时间:2022-04-22 12:00:49

(整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载)

RAC为了实现优雅的信号绑定,可谓使尽浑身解数,不仅是这个,整个RAC中对宏的使用都很有学习价值。我这里简单简单的说明下,我们在实际开发中常用到的宏,有些宏我也没有研究的很透彻,就不班门弄斧了,大家可以参考下别的学习资料。

以下面的例子入手:

RAC(self.noneDataTipView,hidden) = [RACSignal combineLatest:@[bannerSignal,messageSignal] reduce:^id(NSArray *bannerArray, NSArray *messageList){

return @(bannerArray.count || messageList.count);

}];

要实现的功能很简单,就是在bannerSignal与messageSignal这两个信号传来的数组都不包含元素时,将没有内容的提示页面展示出来,当有数据之后,该页面隐藏。

我根据RAC的实现,写了一个简易版的绑定,供学习参考,RAC的实现又关联了许多其他的宏,看起来比较复杂。

QHQSubscriptingAssignmentTrampoline这个类将给我们进行绑定。

- (id)initWithTarget:(id)target;提供了一个初始化方法,需要设置一个绑定的对象,也就是绑定谁。(RAC中还有1个nilValue)

接下来我们就实现那个宏,也是见证奇迹的时刻。

#define QHQ(TARGET, KEYPATH) \

[[QHQSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET)][KEYPATH]

什么鬼?这样就可以了?后面的[KEYPATH]是什么东西?

这其实利用了clang的新特性,允许你像访问字典一样,访问一个对象,但是!对,这是有条件的,你需要重载一个函数,可能大部分OC程序员们对重载不太了解,那么你需要自行百度一下了。

- (void)setObject:(QHQSignal *)signal forKeyedSubscript:(NSString *)keyPath;

上面的方法就是奇迹发生的地方,看看函数的命名,你也明白了,用[]这种角标的形式访问。

简单的实现了下内部(不过功能不太完整),大致思路如此

- (void)setObject:(QHQSignal *)signal forKeyedSubscript:(NSString *)keyPath {

[signal subscribeNext:^(id x) {

[self.target setValue:x forKey:keyPath];

}];

}

之后写个demo测试一下

QHQ(self.view,@"backgroundColor") = [QHQSignal createSignal:^QHQDispose *(id subscriber) {

[subscriber sendNext:[UIColor yellowColor]];

return nil;

}];

运行一下,颜色变了。RAC为了实现这一优雅的绑定,可谓付出颇多心思,对github的开发者们致敬。

补充一下RACKVOChannel这个类的宏,也是这样实现的。