【问题标题】:release for objects on Class method?释放类方法上的对象?
【发布时间】:2020-07-07 13:45:48
【问题描述】:

不使用 ARC,对于使用实例方法初始化的对象,我们会通过 release 调用释放它。

示例:

Sample *obj = [[Sample alloc]init] ;
//   some code here
[obj release] ;

现在对于使用类方法分配的对象应该调用release吗?

示例:

TestSample *testobj = [TestSample initCustom] ;
// some code here

应该有[testobj release]吗?

让我们考虑一下苹果提供的这个标准功能。 endpointWithHostname 是一个类方法。

NWHostEndpoint *pNetHost = [NWHostEndpoint endpointWithHostname:@"0.0.0.0" port:@"21"];

那么,上面的电话应该有[pNetHost release] 吗?

【问题讨论】:

  • 您不能将类方法命名为initCustom。只有真正的初始值设定项,即alloc 之后的东西,应该以init 开头。所以正确重命名initCustom;它应该被称为testSample。现在向我们展示testSample的实现。

标签: objective-c


【解决方案1】:

你说:

对于使用实例方法初始化的对象,我们确实通过release 调用释放它

您调用实例方法这一事实无关紧要。您拥有由名称以 allocnewcopymutableCopy 开头的任何方法返回的任何对象。在您的示例中,您调用了alloc,因此所有权已转移给您。这就是为什么你现在负责打电话给release

但是,如果您调用的实例方法不是以这四个前缀之一开头,则所有权不会转移给您,您也不会调用 release

这一切都总结在Advance Memory Management Programming Guide中,上面写着:

基本内存管理规则

内存管理模型基于对象所有权。任何对象都可能有一个或多个所有者。只要一个对象至少有一个所有者,它就会继续存在。如果一个对象没有所有者,运行时系统会自动销毁它。为确保清楚您何时拥有某个对象,何时不拥有,Cocoa 设置了以下策略:

  • 您拥有自己创建的任何对象

    您使用名称以“alloc”、“new”、“copy”或“mutableCopy”开头的方法创建对象(例如,allocnewObjectmutableCopy)。

  • 您可以使用保留获取对象的所有权

    通常保证接收到的对象在接收它的方法中保持有效,并且该方法也可以安全地将对象返回给它的调用者。您在两种情况下使用retain: (1) 在访问器方法或init 方法的实现中,获取要存储为属性值的对象的所有权; (2) 防止对象因某些其他操作的副作用而失效(如Avoid Causing Deallocation of Objects You’re Using 中所述)。

  • 当您不再需要它时,您必须放弃您拥有的对象的所有权

    您通过向对象发送release 消息或autorelease 消息来放弃对象的所有权。因此,在 Cocoa 术语中,放弃对象的所有权通常称为“释放”对象。

  • 您不得放弃不属于您的对象的所有权

    这只是之前明确规定的政策规则的推论。

你继续问:

让我们考虑一下苹果提供的这个标准功能。 endpointWithHostname 是一个类方法。

 NWHostEndpoint *pNetHost = [NWHostEndpoint endpointWithHostname:@"0.0.0.0" port:@"21"];

所以应该有[pNetHost release] ;上述电话

它是一个类方法这一事实并不重要。关键是方法名不能以allocnewcopymutableCopy开头。这意味着所有权尚未转移给您,因此您无需致电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];
}

但是,上面有两个关键的观察结果:

  1. 我没有以init 开头的方法名称。该前缀只应与初始化方法一起使用,而此方法不是。

    约定是以对象类型的名称开头的方法名称,使用驼峰式(即以小写字母开头)。因此,这个TestSample 类方法名称可能被称为testSample,就像上面一样,而不是initCustom

  2. 由于方法名称不是以allocnewcopymutableCopy 开头,它应该返回一个自动释放对象。因为它是一个autorelease 对象,所以调用者不会调用release(当然,除非它通过调用retain 来声明所有权)。


顺便说一下,静态分析器(shift+command+B;或“产品”»“分析”)非常好在分析手动引用计数代码时。

例如,假设我忘记在上面的testSample 示例中添加autorelease。如果我让 Xcode 分析代码,编译器会告诉我问题所在:

如果我重新添加 autorelease 并重新分析,此警告将消失。

在编写手动引用计数代码时,静态分析器是一个非常宝贵的工具。始终确保您从分析仪获得一份干净的健康证明。

【讨论】:

  • 这是一个详细的答案。谢谢你 。 j 只是跟进:对于新程序,建议使用 ARC 还是我们必须避免使用?
  • 使用 ARC。如果不引入手动引用计数的特性,内存管理就足够困难了。在这一点上,手动引用计数有点不合时宜。 (如果你在讨论 Swift 或 Objective-C,大多数开发人员都在使用 Swift 进行新项目。)
猜你喜欢
  • 2011-06-23
  • 2010-11-18
  • 1970-01-01
  • 2013-03-21
  • 1970-01-01
  • 1970-01-01
  • 2015-04-25
  • 2011-03-04
  • 1970-01-01
相关资源
最近更新 更多