OC 底层 — Block 本质(五):捕获的变量何时销毁?
2024-01-04 02:23:04
作为一个资深的程序猿,了解语言的底层原理至关重要。今天,我们就来探秘 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 代码至关重要。