为什么新的 Objective-C 项目的样板包含自动释放池块,而新的 Swift 项目却没有?
Why does a new Objective-C project's boilerplate contain an autorelease pool block, but a new Swift project doesn't?
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
}
return NSApplicationMain(argc, argv);
}
为什么它如此重要以至于样板文件将其包含在新的 Objective-C 项目中而不是新的 Swift 项目中?
Xcode 的项目模板没有以任何有意义的方式记录,因此无法给出明确的答案 — 但是,有一些可能的促成因素,主要是历史因素。
在引入 ARC 帮助自动化引用计数之前,Objective-C 需要完全手动的内存管理。一种以“自动化”方式更宽松地管理分配的策略是使用 -autorelease
通过将对象添加到全局 (possibly-nested) 池中 最终 处理对象处理池本身时可以处理的对象的数量。这本身是通过使用 -[[NSAutoreleasePool alloc] init]
和 -[NSAutoreleasePool drain]
/-[NSAutoreleasePool release]
创建自动释放池来手动完成的。在对象上调用 -autorelease
时,Obj-C 运行时会找到“最近的”活动自动释放池并将该对象注册到该池中,一旦池消失就会被丢弃。
为了能够 -autorelease
一个对象,必须有一个 autorelease
池实际处于活动状态以捕获该对象 - 它似乎不是这个方式不再,但是 -autorelease
ing 任何池之外的对象用于记录错误(因为除了永远泄漏对象之外,没有什么可以真正安全地完成)。为了避免这种情况,默认的 Xcode 模板在 main
中的整个代码周围添加了一个隐式自动释放池,以确保至少有 一些 池活动以便无错误地捕获对象。 (事实上 ,在引入 @autoreleasepool { ... }
块之前,它在执行包含的代码之前隐式创建一个 autoreleasepool,然后释放它,Xcode 模板用于手动创建一个 autoreleasepool 并在之前释放它从 main
)
返回
ARC 的出现大大减少了自动释放的必要性,以至于 Swift 甚至没有自动释放池的本机概念。 (Swift 中的 autoreleasepool
实际上是 ObjectiveC
模块中的 函数 ,它调用 Obj-C 运行时来包装调用的闭包在自动释放池中。)虽然偶尔有用,但通常不需要它们,除非与 Objective-C 代码接口时仍然使用手动内存管理并出售自动释放的对象,尤其是在紧密循环中。在与(主要是 Apple-based)像 Foundation 这样的框架交互时偶尔会出现这种情况,这些框架可能仍然在考虑手动内存管理的情况下编写组件
还有一个以这种方式创建的全局自动释放池的有用性问题:因为以这种方式创建的最外层自动释放池只会在程序退出前释放对象,释放到默认最外层池的对象在执行期间几乎有效地泄漏,因为没有任何东西可以更早地清理它们
因此,在 Swift 中缺乏需求、缺乏实用性以及 non-existence 自动释放作为 Darwin 平台之外的概念,确实没有太多需要 Xcode 如此直接地在 Swift 项目模板中公开概念,就像它曾经是 Objective-C 所必需的那样。可能为了简洁起见,不支付创建池的费用,也不混淆非 Obj-C 代码作者,这被排除在模板之外。
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
}
return NSApplicationMain(argc, argv);
}
为什么它如此重要以至于样板文件将其包含在新的 Objective-C 项目中而不是新的 Swift 项目中?
Xcode 的项目模板没有以任何有意义的方式记录,因此无法给出明确的答案 — 但是,有一些可能的促成因素,主要是历史因素。
在引入 ARC 帮助自动化引用计数之前,Objective-C 需要完全手动的内存管理。一种以“自动化”方式更宽松地管理分配的策略是使用
-autorelease
通过将对象添加到全局 (possibly-nested) 池中 最终 处理对象处理池本身时可以处理的对象的数量。这本身是通过使用-[[NSAutoreleasePool alloc] init]
和-[NSAutoreleasePool drain]
/-[NSAutoreleasePool release]
创建自动释放池来手动完成的。在对象上调用-autorelease
时,Obj-C 运行时会找到“最近的”活动自动释放池并将该对象注册到该池中,一旦池消失就会被丢弃。为了能够
返回-autorelease
一个对象,必须有一个autorelease
池实际处于活动状态以捕获该对象 - 它似乎不是这个方式不再,但是-autorelease
ing 任何池之外的对象用于记录错误(因为除了永远泄漏对象之外,没有什么可以真正安全地完成)。为了避免这种情况,默认的 Xcode 模板在main
中的整个代码周围添加了一个隐式自动释放池,以确保至少有 一些 池活动以便无错误地捕获对象。 (事实上 ,在引入@autoreleasepool { ... }
块之前,它在执行包含的代码之前隐式创建一个 autoreleasepool,然后释放它,Xcode 模板用于手动创建一个 autoreleasepool 并在之前释放它从main
)ARC 的出现大大减少了自动释放的必要性,以至于 Swift 甚至没有自动释放池的本机概念。 (Swift 中的
autoreleasepool
实际上是ObjectiveC
模块中的 函数 ,它调用 Obj-C 运行时来包装调用的闭包在自动释放池中。)虽然偶尔有用,但通常不需要它们,除非与 Objective-C 代码接口时仍然使用手动内存管理并出售自动释放的对象,尤其是在紧密循环中。在与(主要是 Apple-based)像 Foundation 这样的框架交互时偶尔会出现这种情况,这些框架可能仍然在考虑手动内存管理的情况下编写组件还有一个以这种方式创建的全局自动释放池的有用性问题:因为以这种方式创建的最外层自动释放池只会在程序退出前释放对象,释放到默认最外层池的对象在执行期间几乎有效地泄漏,因为没有任何东西可以更早地清理它们
因此,在 Swift 中缺乏需求、缺乏实用性以及 non-existence 自动释放作为 Darwin 平台之外的概念,确实没有太多需要 Xcode 如此直接地在 Swift 项目模板中公开概念,就像它曾经是 Objective-C 所必需的那样。可能为了简洁起见,不支付创建池的费用,也不混淆非 Obj-C 代码作者,这被排除在模板之外。