block 笔记

2017-05-18  本文已影响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》

上一篇 下一篇

猜你喜欢

热点阅读