OC中链式语法的使用及原理

最初见到链式语法的时候是在masonry库中,当时看到这种写法我是震惊的.一行代码可以赋值多个属性怎么一个爽字了得.一直没有去研究写法的实现.直到我看了一次公开课(为了避嫌,公开课的名字就不说了).在公开课中学到了链式语法的原理和写法.
原理
一般情况下 OC 的调用方法是这样的,比如 tableView 刷新数据的方法:

[tableView reloadData];

当然我们也可以这样写:
tableView.reloadData;

虽然 Xcode 会抛出一个警告,但是并不妨碍方法的执行.那么链式语法仅仅是这么做然后加了一个括号传递参数吗? 很显然不是.如果是有参数的方法我们这么做就会抛出错误.导致无法编译,就像这样:

OC中链式语法的使用及原理
文章图片
QQ20170614-0.png 很遗憾,这种方法不对.如果可以这么做,相信很多讨厌 OC 调用方法方式的人都会开心吧.那么如何能让方法使用小括号接受参数呢?这里就需要借助 block 的语法了
block
还记得 block 怎么传递参数吗?是不是这样:
void(^block)(int i) = ^(int i){ NSLog(@"%d",i); }; block(1);

可以看到 block 使用小括号接受参数.如果一个方法返回值是一个 block 并且使用.语法调用在连接到一起是不是就成了这样:
方法实现:
// 返回一个接受一个 int 类型参数的 block - (void(^)(int))test{void(^block)(int i) = ^(int i){ NSLog(@"%d",i); }; return block; }

方法的正常调用步骤是这样的:
// 我们知道 self.test 就相当于 [self test] // 将 test 方法的返回值赋值给一个 block 变量 再使用变量调用 block 中的代码 void(^block)(int i) =self.test; block(1);

如果连起来写就成了这样
// 因为 self.test 本身就返回了block //括号中的1看似是将值赋给了 test 方法,其实是赋给了 test 方法返回的 block self.test(1);

不得不说大牛的脑洞大的可以.很巧妙的一个方法.初步实现了使用括号传递参数,接下来就要让他们组成链条
链接
有了上面的思路.再考虑让代码的调用形成链条就简单多了,只要让 block 返回 self 自身即可,就像这样:
// 当前类是ViewController类 block 返回 类对象 类对象是不是就可以继续调用 test 方法了 - (ViewController *(^)(int))test{ViewController *(^block)(int i) = ^ViewController *(int i){ NSLog(@"%d",i); return self; }; return block; }

调用的时候就可以很爽的这么写了:
self.test(1).test(2).test(3);

看一下输出结果:
2017-06-14 23:40:04.268258+0800 链式语法[6727:1519931] 1 2017-06-14 23:40:04.268393+0800 链式语法[6727:1519931] 2 2017-06-14 23:40:04.268431+0800 链式语法[6727:1519931] 3

当然 masonry 中链式语法的使用更为复杂,这里只讲一下链式语法的书写原理.
链条的执行顺序
  1. self 调用 test 方法 test 方法返回 block
  2. block 得到小括号中的参数 并执行 block 中的代码
  3. block 返回对象 对象接着调用 test 方法 实际应用中 test 可以是任何这种格式的方法
关于block的一些小细节
  • block 是顺序执行的,并非异步执行,你觉得他是异步执行的很大一部分原因是因为大部分 block 是用来处理异步回调的
  • 书写时如果带返回值的 block 在实现的时候^的位置是在最左边,比如^ViewController *(int i)而不是像声明时一样返回值类型在最左边
  • block 的实现可以不写返回值类型 除非返回值类型是id并且返回值为nil的情况.这时必须在实现声明返回值类型是id,否则报错
id(^block)() = ^id(){ // 返回 nil 必须在实现说明返回值类型是id return nil; } id(^block)() = ^(){ // 返回 不为nil 可以不用声明返回值 return slef; }

Demo地址
【OC中链式语法的使用及原理】https://github.com/JXnan/ChainTest

    推荐阅读