美文网首页
block 笔记

block 笔记

作者: 刻舟求鉴 | 来源:发表于2017-05-18 15:05 被阅读0次

    block简介

    block 其实就是一个值,并且有类型。可以当做 int float 或者 Objective-C对象,也可以赋给变量,然后像使用其他变量那样使用它。只不过定义语法有些特殊。
    下面就是一个block:

    void (^someBlock)() = ^{
       //block implementation here
    };
    

    这段代码定义了一个名为someBlock的变量。由于变量名写在正中间,所以看上去有点怪。

    return_type (^block_name)(parameters)
    

    从左到右依次表示返回类型return_type、block的名字block_name、参数parameters
    按照这种格式定义一个:

    int (^addBlock)(int a,int b) = ^(int a,int b) {
      return a+b;
    };
    

    定义好之后,就可以像函数那样使用了:

    int result = addBlock(1,2); //最终打印result 值为3
    

    block在其声明的范围内,所有的变量都可以为其所获。这也就是说,在它声明范围内的全部变量,在block的里面依然可以使用,block也可以叫做,代码块。使用外部的变量如下:

    int external = 1;
    int (^addBlock)(int a,int b) = ^(int a,int b) {
      return a+b + external;
    };
    // 调用
    int result = addBlock(1,2); //最终打印result 值为4
    

    默认情况下,block使用外部的变量是不可以修改的。如果要修改需要添加修饰符 __block

    __block NSInteger count = 0;
    NSInteger (^numBlock)() = ^{
          count = 1;
          return count;
    };
    

    栈块及堆块(block)

    定义块的时候,其所占的内存区域是非配在栈中的。这就是说,块只在定义它的那个范围内有效。例如下面这样就有危险:

    void (^block) ();
    if(/* some condition*/) {
      block = ^{
        NSLog(@"Block A");
      };
    } else {
      block = ^{
      NSLog(@"Block B");
      };
    }
    block();
    

    定义在ifelse语句中的两个块都分配在栈内存中。编译器会给每个块分配好栈内存,然而等离开相应的范围之后,编译器有可能把分配给块的内存覆写掉。于是,这两个块只能保证在ifelse语句范围内有效。这样写出来的代码可以编译,但是运行起来时而正确,时而错误。若编译器未覆写待执行的块,则程序照常运行,若覆写,则程序崩溃。
    为解决此问题,可给块对象发送copy消息以拷贝之。这样的话,就可以把块从栈复制到堆上。拷贝后的块,可以在定义它的那个范围之外使用,如下:

    void (^block) ();
    if(/* some condition*/) {
      block = [^{
        NSLog(@"Block A");
      } copy];
    } else {
      block =[ ^{
        NSLog(@"Block B");
      } copy];
    }
    block();
    

    参考

    《Effective Objective-C 2.0》

    相关文章

      网友评论

          本文标题:block 笔记

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