ReactiveCocoa源码解析
发布时间:2020-12-15 05:25:43 所属栏目:百科 来源:网络整理
导读:(一)神奇的Macros 先说说RAC中必须要知道的宏 RAC(TARGET,[KEYPATH,[NIL_VALUE]]) 使用: RAC(self.outputLabel,text)=self.inputTextField.rac_textSignal; RAC(self.outputLabel,text,@ "收到nil时就显示我" )=self.inputTextField.rac_textSignal; 这个
(一)神奇的Macros
先说说RAC中必须要知道的宏
使用:
这个宏是最常用的,RAC()总是出现在等号左边,等号右边是一个RACSignal,表示的意义是将一个对象的一个属性和一个signal绑定,signal每产生一个value(id类型),都会自动执行:
数字值会升级为NSNumber *,当setValue:forKeyPath时会自动降级成基本类型(int,float,BOOL等),所以RAC绑定一个基本类型的值是没有问题的
作用是观察TARGET的KEYPATH属性,相当于KVO,产生一个RACSignal
最常用的使用,和RAC宏绑定属性:
上面的代码将label的输出和model的name属性绑定,实现联动,name但凡有变化都会使得label输出
这对宏在 RACEXTScope.h 中定义,RACFramework好像没有默认引入,需要单独import
他们的作用主要是在block内部管理对self的引用:
这个宏为什么这么吊,前面加@,其实就是一个啥都没干的@autoreleasepool {}前面的那个@,为了显眼罢了。
这两个宏一定成对出现,先weak再strong
除了RAC中常用宏的使用,有一些宏的实现方法也很值得观摩。
举个高级点的例子:
要干的一件事,计算一个可变参数列表的长度。
第一反应就是用参数列表的api,va_start va_arg va_end遍历一遍计算个和,但仔细想想,对于可变参数这个事,在编译前其实就已经确定了,代码里括号里有多少个参数一目了然。
RAC中Racmetamarcos.h中就有一系列宏来完成这件事,硬是在预处理之后就拿到了可变参数个数:
这个宏由几个工具宏一层层展开,现在模拟一下展开过程:
1. 假如我们要计算的如下:
2. 于是乎第一层展开后:
intcount=metamacro_at(20,a,c,1)
3. 再看metamacro_at的定义:
4. 于是乎第二层展开后:
intcount=metamacro_at20(a,1);
5. 再看metamacro_at20这个宏干的事儿:
6. 于是乎第三层展开后,相当于截断了前20个参数,留下剩下几个:
intcount=metamacro_head(3,serif; font-size:14px; line-height:25.2000007629395px">
7. 这个metamacro_head:
8. 后面加个0,然后取参数列表第一个,于是乎:
intcount=3;
大功告成。
反正我看完之后感觉挺震惊,宏还能这么用,这样带来的好处不止是将计算在预处理时搞定,不拖延到运行时恶心cpu;但更重要的是编译检查。比如某些可变参数的实现要求可以填2个参数,可以填3个参数,其他的都不行,这样,也只有这样的宏的实现,才能在编译前就确定了错误。
除了上面,还有一个神奇的宏的使用
当使用诸如RAC(self,outputLabel)或RACObserve(self,name)时,发现写完逗号之后,
输入第二个property的时候会出现完全正确的代码提示!这相当神奇。
探究一下,关键的关键是如下一个宏:
这个metamacro_argcount上面说过,是计算
可变参数个数,所以metamacro_if_eq的作用就是判断参数个数,如果个数是1就执行后面的keypath1,若不是1就执行keypath2。
所以
重点说一下keypath2:
先化简,由于Objc里面keypath是诸如”outputLabel.text”的字符串,所以这个宏的返回值应该是个字符串,可以简化成:
先不管”??????”是啥,这里不得不说C语言中一个不大常见的语法(第一个忽略):
inta=0,b=0;
这些都是
逗号表达式的合理用法,第三个最不常用了,c将被b赋值,而a是一个未使用的值,编译器会给出warning。
去除warning的方法很简单,强转成void就行了:
intc=((void)a,serif; font-size:14px; line-height:25.2000007629395px"> 再看上面简化的keypath2宏,返回的就是PATH的字符串字面值了(单#号会将传入值转成字面字符串) |