Objective-C如何阻止捕获非对象值?

时间:2016-10-29 04:11:24

标签: objective-c

int anInteger = 42;

void (^testBlock)(void) = ^{
    NSLog(@"Integer is: %i", anInteger);
};

anInteger = 84;

testBlock();

Integer is: 42

这是Apple官方指南中的一个例子。

现在,对于对象值,它很容易理解,它会保留对它的引用。所以稍后,当它的原始引用更改为指向其他内容时,或者只是被销毁。此引用仍然存在,因此引用计数不会为零,并保留原始值。

但是,对于上面的示例代码,它不是一个对象。该块保留对它的引用,然后该值更改为84.我认为这是对自身的更改而不是其副本,这意味着指针指向的值已更改。怎么还能42岁?

3 个答案:

答案 0 :(得分:9)

从文档的Blocks and Variables部分:

  

以下规则适用于块中使用的变量:

     
      
  1. 可以访问全局变量,包括存在于封闭词法范围内的静态变量。
  2.   
  3. 可以访问传递给块的参数(就像函数的参数一样)。
  4.   
  5. 封闭词法范围本地的堆栈(非静态)变量被捕获为const变量。   它们的值是在程序中的块表达点处获取的。在嵌套块中,从最近的封闭范围捕获值。
  6.   
  7. 使用__block存储修饰符声明的封闭词法范围的局部变量由引用提供,因此是可变的。   任何更改都会反映在封闭的词法范围中,包括在相同的封闭词法范围内定义的任何其他块。这些将在__block Storage Type。
  8. 中详细讨论   
  9. 在块的词法范围内声明的局部变量,其行为与函数中的局部变量完全相同。   每次调用块都会提供该变量的新副本。这些变量又可以在块中包含的块中用作const或by-reference变量。
  10.   

规则3适用于您问题中的代码。

答案 1 :(得分:1)

块引入必要的间接以确保发生这种情况。看似本地但由块捕获的变量实际上是由编译器在堆上分配的。除此之外,这对于该变量能够比其声明的函数的生命周期更长是必要的。

答案 2 :(得分:1)

简而言之:复制整数值。 (更确切地说:结构和对象引用也被复制。但是在对象引用的情况下,它是一个引用。)

顺便说一句:这就是封闭的含义。这就是关闭的原因。他们存在的原因。您想要这个行为。否则,您必须确保在块运行时不会更改值 - 可能是几秒或几分钟。