我认为在为iOS编码时,应该使用属性来访问实例变量,因为这会给内存管理带来诸多好处。
这个建议并不适合我。我发现使用属性而不是普通的旧ivars只需要太多的代码,如果你对内存管理感到满意,我并没有真正看到它的好处。它真的那么重要吗?您管理实例变量的方法是什么?
答案 0 :(得分:77)
没有必要为所有ivars声明属性。我想到了几点:
init
期间保留/复制/分配,然后在dealloc
期间根据需要发布。所以我通常使用属性,但是对于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中获得易于诊断和修复的运行时异常。