2012-09-02 37 views
1

例如: 我们总是这样写的方法1:为什么被调用者返回自动释放对象而不是返回保留对象并让调用者释放对象?

-(NSObject*)giveMeAnObject 
{ 
    return [[[NSObject alloc] init] autorelease]; 
} 

-(void)useObject 
{ 
    NSObject *object = [self giveMeAnObject]; 
    //use that object 
} 

,但我们为什么不写这样的方式2:

-(NSObject*)giveMeAnObject 
{ 
    return [[NSObject alloc] init]; 
} 

-(void)useObject 
{ 
    NSObject *object = [self giveMeAnObject]; 
    //use that object 
    [object release]; 
} 

可可SDK做这样的事情的方式1,我这就是为什么我们都使用方式1,它已经成为一种编码习惯。 但我只是认为,如果约定是方式2,我们可以获得很少的性能改进。

那么除编程约定外,还有其他什么原因使用方式1代替方式2吗?

+0

总是有机会忘记释放它。在代码中将分配和释放分离太远是潜在的错误来源。特别是当你在一个函数中分配一些东西作为返回对象时。 – nhahtdh

+0

这是一个所有权问题。在情况1中,自动释放的对象由方法返回,因为它可能属于类或框架,而不是调用者。 – CodaFi

回答

4

返回一个自动释放对象是一种抽象的形式 - 开发人员的方便,所以他/她不必考虑返回对象的引用计数 - 因此会导致更少的特定错误类别(尽管您也可以说autorelease池引入了新的类别的错误或复杂性)。它可以真正简化客户端代码,但是,可能会有性能问题。当不需要进行参考操作时,它也可以用作抽象优化 - 考虑对象何时持有返回的实例并且不需要进行保留或复制。尽管链接语句可以被过度使用,但这种做法对于链接语句也很方便。

此外,确定引用计数错误的静态分析器对于这些库和程序中的一些来说是相对较新的。 Autorelease池在ARC之前,对objc对象的引用计数进行多年的静态分析 - 确保您的引用计数正确,现在使用这些工具更简单。他们能够检测到许多错误。

当然,如果您喜欢简单的返回自动释放对象 - 使用ARC,您可以返回更少的自动释放对象,而无需引入抽象的autorelease池错误。

使用统一的所有权语义也简化了程序。如果抽象选择器或选择器集合总是使用相同的语义返回,那么它确实可以简化一些通用形式。例如 - 如果传递给performSelector:的一组选择器具有不同的所有权返回语义,则会增加很多复杂性。如此统一的所有权归还可以真正简化一些更“通用”的实现。

性能:引用计数操作(保留/释放)可能相当重要 - 尤其是如果您习惯于在较低级别工作。但是,当前的自动释放池实现速度非常快。它们最近被更新了,并且比以前更快。编译器和运行库使用几个特殊的快捷键来降低这些成本。保持autorelease池的大小也是一个好主意 - 特别是在移动设备上。创建一个autorelease池非常快。实际上,您可能会从自动释放操作本身增加零个百分点到几个百分点(即消耗的时间比objc_msgSend +变体少得多)。有些测试甚至跑得快一点。这不是许多人将从中获得的优化。在典型情况下,它不会成为低挂果实,而且在真实计划中衡量这种变化的效果和地点实际上相对困难 - 基于我在bbum提到下面的变化之后所做的一些测试。所以测试范围有限,但MRC和ARC似乎更好/更快。

因此,如果您正在执行自己的引用计数操作,很多情况都归结于您想要承担的责任级别。对于大多数人来说,它不应该改变他们的写作方式。我认为本地化内存问题,更多确定性的对象破坏,以及更可预测的堆大小是人们可能喜欢的主要原因如果您在现代系统上运行,则返回“拥有”(+1)引用计数。即使如此,在很多情况下,运行时和编译器都会为您减少这个数量(请参阅bbum的答案+1)。尽管自动释放池大约一样快,但我现在不打算比现在更多地使用它们 - 所以仍然有合理的理由尽量减少使用它们,但原因正在减少。

+1

+1 ...我会磨练*重大*索赔。他们*可能会产生重大影响,但这通常表明架构中存在其他问题。在近期发布的版本中,autorelease的成本大大降低。 – bbum

+0

@bbum ahoy - 谢谢你指出。花了一些时间与分析器并相应地更新了答案。干杯。 – justin

3

您是否衡量了性能优势?你有一个可量化的情况,其中autorelease与CF风格的调用者必须释放有可衡量的性能影响?

如果不是,则模拟点。如果是这样,我敢打赌,有一个系统性的架构问题,远远超越autorelease而不是。

无论如何,如果你采用ARC,autorelease的“成本”是最小化。编译器和运行库实际上可以跨方法调用优化autorelease。

0

主要有三个方面的原因:

  1. 它规定的取得所有权的概念。
  2. 它消除了悬挂指针的问题。
  3. 它返回在本地自动发布池中创建的对象,从而提高性能。