OC中的block闭包性问题

来源:互联网 发布:云警联网报警主机编程 编辑:程序博客网 时间:2024/06/05 14:35

学习了OC中的block代码段的用法,非常的好用,功能有些类似于一个函数指针,又可以作为一块代码段。

学习了其中的闭包性,记一下:

在block内部,可以像普通函数一样访问数据:局部变量、传递给block的参数,全局变量/函数。并且由于block具有闭包性,所以还能访问非局部变量(non-local variable)。非局部变量定义在block之外,但是在block内部有它的作用域。例如,getFullCarName可以使用定义在block前面的make变量:

  1. NSString *make = @"Honda";
  2. NSString *(^getFullCarName)(NSString *) = ^(NSString *model) {
  3. return [make stringByAppendingFormat:@" %@", model];
  4. };
  5. NSLog(@"%@", getFullCarName(@"Accord")); // Honda Accord
非局部变量会以const变量被拷贝并存储到block中,也就是说block对其是只读的。如果尝试在block内部给make变量赋值,会抛出编译器错误。
以const拷贝的方式访问非局部变量,意味着block实际上并不是真正的访问了非局部变量——只不过在block中创建了非局部变量的一个快照。当定义block时,无论非局部变量的值是什么,都将被冻结,并且block会一直使用这个值,即使在之后的代码中修改了非局部变量的值。下面通过代码来看看,在创建好block之后,修改make变量的值,会发生什么:
  1. NSString *make = @"Honda";
  2. NSString *(^getFullCarName)(NSString *) = ^(NSString *model) {
  3. return [make stringByAppendingFormat:@" %@", model];
  4. };
  5. NSLog(@"%@", getFullCarName(@"Accord")); // Honda Accord
  6. // Try changing the non-local variable (it won't change the block)
  7. make = @"Porsche";
  8. NSLog(@"%@", getFullCarName(@"911 Turbo")); // Honda 911 Turbo
block的闭包性为block与上下文交互的时候带来极大的便利性,当block需要额外的数据时,可以避免使用参数——只需要简单的使用非局部变量即可。
修改非局部变量
冻结中的非局部变量是一个常量值,这也是一种默认的安全行为——因为这可以防止在block中的代码对非局部变量做了意外的修改。那么如果我们希望在block中对非局部变量值进行修改要如何做呢——用__block存储修饰符(storage modifier)来声明非局部变量:
  1. __block NSString *make = @"Honda";
这将告诉block对非局部变量做引用处理,在block外部make变量和内部的make变量创建一个直接的链接(direct link)。现在就可以在block外部修改make,然后反应到block内部,反过来,也是一样。
通过引用的方式访问非局部变量
这跟普通函数中的静态局部变量(static local variable)类似,用__block修饰符声明的变量可以记录着block多次调用的结果。例如下面的代码创建了一个block,在block中对i进行累加。
  1. __block int i = 0;
  2. int (^count)(void) = ^ {
  3. i += 1;
  4. return i;
  5. };
  6. NSLog(@"%d", count()); // 1
  7. NSLog(@"%d", count()); // 2
  8. NSLog(@"%d", count()); // 3

0 0