你说:
对于使用实例方法初始化的对象,我们确实通过release 调用释放它
您调用实例方法这一事实无关紧要。您拥有由名称以 alloc、new、copy 或 mutableCopy 开头的任何方法返回的任何对象。在您的示例中,您调用了alloc,因此所有权已转移给您。这就是为什么你现在负责打电话给release。
但是,如果您调用的实例方法不是以这四个前缀之一开头,则所有权不会转移给您,您也不会调用 release。
这一切都总结在Advance Memory Management Programming Guide中,上面写着:
基本内存管理规则
内存管理模型基于对象所有权。任何对象都可能有一个或多个所有者。只要一个对象至少有一个所有者,它就会继续存在。如果一个对象没有所有者,运行时系统会自动销毁它。为确保清楚您何时拥有某个对象,何时不拥有,Cocoa 设置了以下策略:
你继续问:
让我们考虑一下苹果提供的这个标准功能。 endpointWithHostname 是一个类方法。
NWHostEndpoint *pNetHost = [NWHostEndpoint endpointWithHostname:@"0.0.0.0" port:@"21"];
所以应该有[pNetHost release] ;上述电话
它是一个类方法这一事实并不重要。关键是方法名不能以alloc、new、copy或mutableCopy开头。这意味着所有权尚未转移给您,因此您无需致电release。在这种情况下,它返回一个自动释放对象,因此当自动释放池耗尽时,它将为您释放。
显然,如果您想声明对 pNetHost 对象的所有权,您可以通过调用 retain 来实现(当然,此时您将负责最终调用 release 来抵消它retain)。
现在,让我们考虑一下您的示例:
TestSample *testobj = [TestSample initCustom];
// some code here
应该有[testobj release]吗?
没有。但是,让我们通过查看您称为initCustom 的方法的实现来回答这个问题。可以这样实现:
+ (instancetype)testSample {
TestSample *obj = [[self alloc] init];
// perhaps more customization of `obj` here
return [obj autorelease];
}
但是,上面有两个关键的观察结果:
-
我没有以init 开头的方法名称。该前缀只应与初始化方法一起使用,而此方法不是。
约定是以对象类型的名称开头的方法名称,使用驼峰式(即以小写字母开头)。因此,这个TestSample 类方法名称可能被称为testSample,就像上面一样,而不是initCustom。
-
由于方法名称不是以alloc、new、copy 或mutableCopy 开头,它应该返回一个自动释放对象。因为它是一个autorelease 对象,所以调用者不会调用release(当然,除非它通过调用retain 来声明所有权)。
顺便说一下,静态分析器(shift+command+B;或“产品”»“分析”)非常好在分析手动引用计数代码时。
例如,假设我忘记在上面的testSample 示例中添加autorelease。如果我让 Xcode 分析代码,编译器会告诉我问题所在:
如果我重新添加 autorelease 并重新分析,此警告将消失。
在编写手动引用计数代码时,静态分析器是一个非常宝贵的工具。始终确保您从分析仪获得一份干净的健康证明。