每个伊娃都必须是财产吗?

时间:2011-02-17 15:50:20

标签: objective-c ios properties instance-variables

我认为在为iOS编码时,应该使用属性来访问实例变量,因为这会给内存管理带来诸多好处。

这个建议并不适合我。我发现使用属性而不是普通的旧ivars只需要太多的代码,如果你对内存管理感到满意,我并没有真正看到它的好处。它真的那么重要吗?您管理实例变量的方法是什么?

4 个答案:

答案 0 :(得分:77)

没有必要为所有ivars声明属性。我想到了几点:

  • 如果ivar仅在对象的生命周期中被分配一次,那么通过声明属性你并没有真正获得任何东西。只需在init期间保留/复制/分配,然后在dealloc期间根据需要发布。
  • 如果要经常更改ivar,声明属性并始终使用访问器将更容易避免内存管理错误。
  • 如果属性和ivars是私有的,您可以在.m文件而不是.h文件中声明类扩展中的属性。
  • 当定位iOS 4.0+时,如果定义属性并合成访问者,则无需在标题中声明ivars。

所以我通常使用属性,但是对于NSMutableArray期间对象分配的init之类的东西并且用来容纳一堆whatevers,我将使用一个普通的旧ivar,因为我会永远不要重新分配伊娃。

答案 1 :(得分:51)

虽然丹尼尔的答案是正确的,但我认为它错过了一个重要的观点。即:

  

我发现使用属性代替   普通的旧伊娃只需要太多   代码,我真的没有看到   如果你觉得舒服,那就有好处   记忆管理。

好处是一致性;一致的内存管理和一致的行为。

值得注意的是,这两行代码在运行时实际上可能具有极其不同的行为:

iVar = [foo retain];
self.iVar = foo;

第一个是实例变量的直接设置,不会有任何变更通知。第二个遍历setter,因此,在设置时保留任何子类自定义,确保向属性的任何观察者通知更改

如果您在整个代码中直接使用ivars(在类的内部 - 如果您直接从外部那个实例使用实例的ivars,那么......任何承包商都会在您的代码库中工作应该加倍他们的费率;),然后您必须手动处理更改通知传播(通常通过调用willChangeValueForKey: / didChangeValueForKey明确设计您的应用程序以避免使用机制依赖于键值观察。

你说“需要太多代码”。我没有看到;在上面两行代码中,点语法是较少的字符。即使使用传统语法调用setter方法也会减少代码。

不要忽视集中内存管理的价值;在无数的呼叫站点和崩溃的城市中发生了一次意外遗漏。

答案 2 :(得分:3)

属性只是语法糖,可以避免一遍又一遍地编写相同的方法。 使用属性,您可以使用一个setter来释放旧对象并免费保留新对象。

答案 3 :(得分:1)

对于私有字段 - 我建议仅使用直接ivars为原始类型(BOOL / int / float等)是安全的。我找到了一个很好的做法,包括与属性中的内存管理相关的一切 - 甚至很少使用的字段。这种方法的另一个好处是IDE通常会以不同的方式突出显示直接的ivars访问,因此您总是可以很好地分离简单的标量字段和对象类型字段。

与此相反,我强烈反对类公共接口中的任何直接ivars 。由于语言的动态特性,它可能导致极难找到,本地化和修复的运行时错误。请考虑以下层次结构

@interface BaseControl
...
@end

@interface Label : BaseControl
...
@end

@interface Button : BaseControl {
  @public
    BOOL enabled;
}
@end

和代码段

- (void)enableAllButtons {
    NSArray *buttons = [self getAllButtons];   // expected to contain only Button instances
    for (Button *button in buttons) {
        button->enabled = YES;
    }
} 

现在想象-getAllButtons逻辑中的某个地方有一个错误,你也会在该数组中返回一些Label - 所以那些Label类实例将被分配的ivar缺失。可能令人惊讶的事实是-enableAllButtons在这种情况下不会崩溃。但在那时,那些Label实例内部结构已损坏,而导致未定义的行为,并在其他地方使用时崩溃。

就像内存管理中的一些常见问题(通常是悬挂指针) - 这种问题很难找到和本地化 - 因为错误的出现通常很遥远(在时间,代码或应用流程方面) )从这个地方,造成错误。但是对于这个特殊的问题,你甚至没有方便的工具(如泄漏/僵尸分析器等)来帮助你进行本地化和修复 - 即使你学会了如何重现它并且可以轻松地调查错误的状态。

显然,如果您使用@property (assign) BOOL enabled;,您将在-enableAllButtons中获得易于诊断和修复的运行时异常。