[英]Must every ivar be a property?
我看到它在为iOS编码时建议应该使用属性来访问实例变量,因为这会给内存管理带来诸多好处。
这个建议并不适合我。 我发现使用属性而不是普通的旧ivars只需要太多的代码,如果你对内存管理感到满意,我并没有真正看到它的好处。 它真的那么重要吗? 您管理实例变量的方法是什么?
没有必要为所有ivars声明属性。 想到几点:
init
期间保留/复制/分配,然后在dealloc
期间根据需要释放。 所以我通常使用属性,但对于一个对象在init
期间分配的NSMutableArray
并用于保存一堆whatevers的东西,我将使用一个普通的旧ivar,因为我永远不会重新分配ivar。
虽然丹尼尔的答案是正确的,但我认为它错过了一个重要的观点。 即:
我发现使用属性而不是普通的旧ivars只需要太多的代码,如果你对内存管理感到满意,我并没有真正看到它的好处。
好处是一致性; 一致的内存管理和一致的行为。
值得注意的是,这两行代码在运行时实际上可能具有极其不同的行为:
iVar = [foo retain];
self.iVar = foo;
第一个是实例变量的直接设置,不会有更改通知。 第二个遍历setter,因此,在设置时保留任何子类自定义, 并确保向属性的任何观察者通知更改 。
如果您在整个代码中直接使用ivars(在类的内部 - 如果您直接从该实例外部使用实例的ivars,那么......任何处理您的代码库的承包商应该加倍他们的费率;),那么您必须或者也可以手动处理更改通知传播(通常通过调用willChangeValueForKey:
/ didChangeValueForKey
) 或明确设计应用程序以避免使用依赖于键值观察的机制。
你说“需要太多代码”。 我没有看到; 在上面两行代码中,点语法是较少的字符。 即使使用传统语法调用setter方法也会减少代码。
并且不要忽视集中内存管理的价值; 在无数的呼叫站点和崩溃的城市中发生了一次意外遗漏。
属性只是语法糖,可以避免一遍又一遍地编写相同的方法。 使用属性,您可以使用一个setter来释放旧对象并免费保留新对象。
对于私有字段 - 我建议仅对原始类型(BOOL / int / float等)使用直接ivars是安全的。 我找到了一个很好的做法,包括与属性中的内存管理相关的所有内容 - 甚至很少使用的字段。 这种方法的另一个好处是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中获得易于诊断和修复运行时异常的信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.