加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ReactiveCocoa源码解析

发布时间:2020-12-15 04:50:55 所属栏目:百科 来源:网络整理
导读:(一)神奇的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中必须要知道的宏
 
 
  1. RAC(TARGET,[KEYPATH,[NIL_VALUE]])
使用:
 
  
  • RAC(self.outputLabel,text)=self.inputTextField.rac_textSignal;
  • RAC(self.outputLabel,text,@"收到nil时就显示我")=self.inputTextField.rac_textSignal;
  • 这个宏是最常用的,RAC()总是出现在等号左边,等号右边是一个RACSignal,表示的意义是将一个对象的一个属性和一个signal绑定,signal每产生一个value(id类型),都会自动执行:
     
      
  • [TARGETsetValue:value?:NIL_VALUEforKeyPath:KEYPATH];
  • 数字值会升级为NSNumber *,当setValue:forKeyPath时会自动降级成基本类型(int,float,BOOL等),所以RAC绑定一个基本类型的值是没有问题的
     
      
  • RACObserve(TARGET,KEYPATH)
  • 作用是观察TARGET的KEYPATH属性,相当于KVO,产生一个RACSignal
    最常用的使用,和RAC宏绑定属性:
       上面的代码将label的输出和model的name属性绑定,实现联动,name但凡有变化都会使得label输出 
     
     
      
  • @weakify(Obj);
  • @strongify(Obj);
  • 这对宏在 RACEXTScope.h 中定义,RACFramework好像没有默认引入,需要单独import
    他们的作用主要是在block内部管理对self的引用
     
      
  • @weakify(self);//定义了一个__weak的self_weak_变量
  • [RACObserve(self,name)subscribeNext:^(NSString*name){
  • @strongify(self);//局域定义了一个__strong的self指针指向self_weak
  • self.outputLabel.text=name;
  • }];
  • 这个宏为什么这么吊,前面加@,其实就是一个啥都没干的@autoreleasepool {}前面的那个@,为了显眼罢了。
    这两个宏一定成对出现,先weak再strong
    除了RAC中常用宏的使用,有一些宏的实现方法也很值得观摩。
    举个高级点的例子:
    要干的一件事,计算一个可变参数列表的长度。
    第一反应就是用参数列表的api,va_start va_arg va_end遍历一遍计算个和,但仔细想想,对于可变参数这个事,在编译前其实就已经确定了,代码里括号里有多少个参数一目了然。
    RAC中Racmetamarcos.h中就有一系列宏来完成这件事,硬是在预处理之后就拿到了可变参数个数:
     
      
  • #definemetamacro_argcount(...)
  • metamacro_at(20,__VA_ARGS__,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
  • 这个宏由几个工具宏一层层展开,现在模拟一下展开过程:
    1. 假如我们要计算的如下:
     
      
  • intcount=metamacro_argcount(a,b,c);
  • 2. 于是乎第一层展开后:
    intcount=metamacro_at(20,a,c,1) 
      
     
    3. 再看metamacro_at的定义:
     
      
  • #definemetamacro_at(N,...)metamacro_concat(metamacro_at,N)(__VA_ARGS__)
  • //下面是metamacro_concat做的事(简写一层)
  • #definemetamacro_concat_(A,B)A##B
  • 4. 于是乎第二层展开后:
    intcount=metamacro_at20(a,1); 
      
     
    
    5. 再看metamacro_at20这个宏干的事儿:
     
      
  • #definemetamacro_at20(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,...)metamacro_head(__VA_ARGS__)
  • 6. 于是乎第三层展开后,相当于截断了前20个参数,留下剩下几个:
    intcount=metamacro_head(3,serif;font-size:14px;line-height:25.2000007629395px;">
       7. 这个metamacro_head: 
      
     
     
      
  • #definemetamacro_head(...)metamacro_head_(__VA_ARGS__,0)
  • #definemetamacro_head_(FIRST,...)FIRST
  • 8. 后面加个0,然后取参数列表第一个,于是乎:
    intcount=3; 
      
     
    大功告成。
    反正我看完之后感觉挺震惊,宏还能这么用,这样带来的好处不止是将计算在预处理时搞定,不拖延到运行时恶心cpu;但更重要的是编译检查。比如某些可变参数的实现要求可以填2个参数,可以填3个参数,其他的都不行,这样,也只有这样的宏的实现,才能在编译前就确定了错误。
    除了上面,还有一个神奇的宏的使用
    当使用诸如RAC(self,outputLabel)或RACObserve(self,name)时,发现写完逗号之后, 输入第二个property的时候会出现完全正确的代码提示!这相当神奇。
    探究一下,关键的关键是如下一个宏:
     
      
  • #definekeypath(...)
  • metamacro_if_eq(1,metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))
  • 这个metamacro_argcount上面说过,是计算 可变参数个数,所以metamacro_if_eq的作用就是判断参数个数,如果个数是1就执行后面的keypath1,若不是1就执行keypath2。
    所以 重点说一下keypath2
     
      
  • #definekeypath2(OBJ,PATH)
  • (((void)(NO&&((void)OBJ.PATH,NO)),#PATH))
  • 先化简,由于Objc里面keypath是诸如”outputLabel.text”的字符串,所以这个宏的返回值应该是个字符串,可以简化成:
     
      
     
    先不管”??????”是啥,这里不得不说C语言中一个不大常见的语法(第一个忽略):
    inta=0,b=0; 
      
  • a=1,b=2;
  • intc=(a,b);
  • 这些都是 逗号表达式的合理用法,第三个最不常用了,c将被b赋值,而a是一个未使用的值,编译器会给出warning。
    去除warning的方法很简单,强转成void就行了:
    intc=((void)a,serif;font-size:14px;line-height:25.2000007629395px;">
       再看上面简化的keypath2宏,返回的就是PATH的字符串字面值了(单#号会将传入值转成字面字符串) 
      
     
     
      
  • ((( 对传入的第一个参数OBJ和第二个正要输入的PATH做了点操作,这也正是为什么输入第二个参数时编辑器会给出正确的代码提示。强转void就像上面说的去除了warning。
    但至于为什么加入与NO做&&,我不太能理解,我测试时其实没有时已经完成了功能,可能是作者为了屏蔽某些隐藏的问题吧。
    这个宏的巧妙的地方就在于使得编译器以为我们要输入“点”出来的属性,保证了输入值的合法性(输了不存在的property直接报错的),同时利用了逗号表达式取逗号最后值的语法返回了正确的keypath。
    总之
    RAC对宏的使用达到了很高的水平,还有诸如RACTuplePack,RACTupleUnpack的宏就不细说了,值得研究。
    PS:上面介绍的metamacro和@strongify等宏确切来说来自RAC依赖的extobjc,作者是Justin Spahr-Summers,正是RAC作者之一。

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    • 推荐文章
        热点阅读