返回

OC 底层 — Block 本质(五):捕获的变量何时销毁?

IOS

作为一个资深的程序猿,了解语言的底层原理至关重要。今天,我们就来探秘 Objective-C 中 Block 的本质,具体聚焦于一个颇具争议性的问题:捕获的变量何时销毁?

Block 的本质

在 Objective-C 中,Block 是一种特殊类型的匿名函数,它可以捕获周围作用域中的变量。我们举个例子,看看这段代码:

void (^block)(void) = ^{
  NSLog(@"%@", person);
};

这段代码定义了一个 Block,该 Block 捕获了变量 person。当 Block 被调用时,它会打印 person 的值。

捕获变量的销毁时机

关于捕获的变量何时销毁,在 Objective-C 社区中一直存在争论。一些人认为它们会在 Block 销毁时销毁,而另一些人则认为它们会在其作用域结束时销毁。

在 ARC(自动引用计数)环境下 ,捕获的变量会在 Block 销毁时销毁。这是因为 Block 本身是一个对象,它有一个强引用指向捕获的变量。因此,当 Block 被销毁时,它对捕获变量的强引用也会被销毁,从而导致捕获变量被销毁。

在 MRC(手动引用计数)环境下 ,情况则有所不同。在 MRC 中,捕获的变量会在其作用域结束时销毁。这是因为 Block 在 MRC 中不是对象,因此它不会有强引用指向捕获的变量。因此,当 Block 的作用域结束时,捕获的变量不再被任何东西引用,从而被销毁。

一个有趣的例子

为了更好地理解捕获变量的销毁时机,我们来看一个有趣的例子:

void (^block)(void) = ^{
  __autoreleasing id person = [[Person alloc] init];
  NSLog(@"%@", person);
};

block();

在这个例子中,Block 捕获了变量 person,而 person 是一个 __autoreleasing 对象。__autoreleasing 对象会在其作用域结束时自动释放。

在 ARC 环境下,这段代码不会打印任何内容,因为 person 会在 Block 销毁时被销毁。而在 MRC 环境下,这段代码会打印 person 的值,因为 person 会在其作用域结束时被销毁,而不是在 Block 销毁时被销毁。

总结

捕获的变量销毁的时机取决于 Objective-C 环境的类型。在 ARC 环境下,它们会在 Block 销毁时销毁,而在 MRC 环境下,它们会在其作用域结束时销毁。理解这种差异对于编写健壮且高效的 Objective-C 代码至关重要。