美文网首页
ReactiveCocoa 中的@keypath宏

ReactiveCocoa 中的@keypath宏

作者: 九昍 | 来源:发表于2018-06-06 22:24 被阅读0次

    简单的解析一下ReactiveCocoa的@keypath宏

    在xcode里面写下下面两行代码
    @keypath(self.testKeyPath);
    @keypath(self, testKeyPath);
    

    在Xcode里面找到下面的选项,可以看到预编译以后的代码


    这是代码的对应关系
    1.
    @keypath(self.testKeyPath);
    @(((void)(__objc_no && ((void)self.testKeyPath, __objc_no)), strchr("self.testKeyPath", '.') + 1));
    
    2.
    @keypath(self, testKeyPath);
    @(((void)(__objc_no && ((void)self.testKeyPath, __objc_no)), "testKeyPath"));
    

    我们从外到内一层一层的看第一个表达式

    1>最外层是@(),负责把c语言字符串转为NSString类型,最后整个表达式等价于@("testKeyPath")

    2>去掉最外层,得到的是

    ((void)(__objc_no && ((void)self.testKeyPath, __objc_no)), 
    strchr("self.testKeyPath", '.') + 1)
    

    这是一个逗号表达式,左边用来校验表达式是否合法,如果不合法,编写代码的时候编辑器会给出提示


    而右边的表达式是最终获得的c语言字符串,

    strchr("self.testKeyPath", '.') + 1)
    

    strchr("self.testKeyPath", '.')返回的是".testKeyPath"的指针,加1以后就拿到了”testKeyPath"

    接下来看下左边的表达式是怎么校验表达式合法性的。

    (void)(__objc_no && ((void)self.testKeyPath, __objc_no))
    

    首先普及一条规则,逗号表达式左边的值加上void以后,逗号表达式会忽略左边的值。

    我们从简单到复杂写这个宏,看会发生什么

    首先,最简单的,我们可以写成

    @(((void)self.testKeyPath, "testKeyPath"))
    

    这样写会导致testKeyPath方法被调用一次,这无疑意味着会增加性能损耗,这并不是我们想要的

    所以可以继续扩展一下,写成

    @(((void)(NO&&self.testKeyPath), "testKeyPath"))
    

    用短路与,防止self.testKeyPath被执行,然而还是编译不过,NO的类型和self.testKeyPath不匹配

    这时候我们需要&&后面的表达式也返回一个BOOL类型。

    藉由前面的经验,可以写成((void)self.testKeyPath, NO),用void忽略逗号左边的值,此时表达式的值为NO是一个BOOL类型。

    于是,整个表达式变成了

    @(((void)(NO&&((void)self.testKeyPath, NO)), "testKeyPath"))
    

    和最开始的表达式完全一致。

    ReactiveCocoa使用如此巧妙的方式实现了@keypath宏,让它既可以拥有代码提示,又可以在编译时校验表达式的合法性,让我们不至于写出错误的keyPath

    相关文章

      网友评论

          本文标题:ReactiveCocoa 中的@keypath宏

          本文链接:https://www.haomeiwen.com/subject/xycvsftx.html