简而言之:
通常,您在从外部访问对象时使用属性。然后,性能不应该是至关重要的,因为您可能没有执行繁重的工作。如果 KVO 是一个问题,您可能需要检查您的应用程序的设计。从对象本身来说,最好直接访问ivars,这种情况下KVO是无关紧要的。
更多细节:
最近在苹果邮件列表中讨论了这个话题:
何时使用属性与 ivars
特别是 Jens Alfke(前苹果员工)的回答:
- 作为类的公共 API 的一部分。
- 作为类实现中的抽象
- 作为更改实例变量的便捷瓶颈——例如,如果您想在每次更改变量时触发其他内容,则将其设置为属性而不是直接写入 ivar 会很有用。
- 在非 ARC 代码中,当您分配新值时,它可能是一种管理保留/释放舞蹈的便捷方式(但这个问题随着 ARC 而消失。)
我见过只为所有内部状态声明和使用属性的代码——我认为这是个坏主意。这真的很浪费 CPU 时间和代码大小,而且现在我们有了 ARC,它不再给你买任何东西了。
另外,请注意,除了 KVO 之外,还有其他性能问题。John McCall(现任 Apple 员工)表示:
属性以多种方式影响性能:
- 正如已经讨论过的,发送消息来执行加载/存储比仅执行加载/存储内联要慢。
- 发送消息进行加载/存储也需要在 i-cache 中保留更多代码:即使 getter/setter 除了加载/存储之外添加了零个额外指令,也会有一半- 调用者中的十几个额外指令来设置消息发送和处理结果。
- 发送消息会强制将该选择器的条目保留在方法缓存中,并且该内存通常保留在 d-cache 中。这会增加启动时间,增加应用程序的静态内存使用量,并使上下文切换更加痛苦。由于方法缓存特定于对象的动态类,因此在其上使用 KVO 的次数越多,这个问题就越严重。
- 发送消息会强制函数中的所有值溢出到堆栈中(或保存在被调用者保存寄存器中,这只是意味着在不同的时间溢出)。
- 发送消息可能会产生任意副作用,因此会强制编译器重置其关于非本地内存的所有假设。
- 消息发送可以有任意的副作用,因此不能被提升、沉没、重新排序、合并或消除。
- 在 ARC 中,消息发送的结果将始终由被调用者或调用者保留,即使是 +0 返回:即使该方法不保留/自动释放其结果,调用者也不知道并且有尝试采取措施防止结果自动释放。这永远无法消除,因为消息发送不是静态可分析的。
- 在 ARC 中,由于 setter 方法通常将其参数设为 +0,因此无法将该对象的保留(如上所述,ARC 通常具有)“转移”到 ivar,因此该值通常必须得到保留/释放两次。
当然,这并不意味着它们总是不好的——使用属性有很多好的理由。请记住,与许多其他语言功能一样,它们不是免费的。
除了 KVO,在设计应用程序时还要考虑这些。