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

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


原理

一般情况下 OC 的调用方法是这样的,比如 tableView 刷新数据的方法:

    [tableView reloadData];

当然我们也可以这样写:

    tableView.reloadData;

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


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地址

https://github.com/JXnan/ChainTest

你可能感兴趣的:(OC中链式语法的使用及原理)