最初见到链式语法的时候是在masonry库中,当时看到这种写法我是震惊的.一行代码可以赋值多个属性怎么一个爽字了得.一直没有去研究写法的实现.直到我看了一次公开课(为了避嫌,公开课的名字就不说了).在公开课中学到了链式语法的原理和写法.
原理
一般情况下 OC 的调用方法是这样的,比如 tableView 刷新数据的方法:
[tableView reloadData];
当然我们也可以这样写:
tableView.reloadData;
虽然 Xcode 会抛出一个警告,但是并不妨碍方法的执行.那么链式语法仅仅是这么做然后加了一个括号传递参数吗? 很显然不是.如果是有参数的方法我们这么做就会抛出错误.导致无法编译,就像这样:
很遗憾,这种方法不对.如果可以这么做,相信很多讨厌 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 中链式语法的使用更为复杂,这里只讲一下链式语法的书写原理.
链条的执行顺序
- self 调用 test 方法 test 方法返回 block
- block 得到小括号中的参数 并执行 block 中的代码
- 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;
}