2

我不使用 KVO,主要是出于性能原因,所以我想确保我正确禁用它。

来自 Apple Key-Value Observing Programming Guide

自动支持(针对 KVO)由 NSObject 提供,默认情况下可用于符合键值编码的类的所有属性。通常,如果您遵循标准的 Cocoa 编码和命名约定,您可以使用自动更改通知——您不必编写任何额外的代码。

这是否意味着 Xcode 生成的每个属性都实现willChangeValueForKeydidChangeValueForKey方法?

如果是这样,是否有某种方法(某些标志或其他东西)可以禁用此行为?我一直在使用accessInstanceVariablesDirectly并返回 NO,但我不确定这是否足够好。

4

5 回答 5

10

我不使用KVO。

你不能真正知道这一点。Cocoa 框架类或其他外部代码可能在您不知情的情况下依赖于 KVO。

此外,NSObject 的 KVO 使用一种称为 isa-swizzling 的技术,通过动态地对观察到的对象进行子类化来自动增强观察到的对象。这意味着没有观察到的对象没有开销。

您的其他问题:

accessInstanceVariablesDirectly仅在 KVC 中使用,与 KVO 无关。覆盖它没有性能优势。

这是否意味着 Xcode 生成的每个属性都 实现willChangeValueForKeydidChangeValueForKey方法?

是的,每个对象都会响应这些方法。但是这些方法的存在并不意味着性能会受到任何影响。通常甚至不调用这些方法。

于 2013-04-05T10:26:44.233 回答
3

简而言之:

通常,您在从外部访问对象时使用属性。然后,性能不应该是至关重要的,因为您可能没有执行繁重的工作。如果 KVO 是一个问题,您可能需要检查您的应用程序的设计。从对象本身来说,最好直接访问ivars,这种情况下KVO是无关紧要的。

更多细节:

最近在苹果邮件列表中讨论了这个话题:
何时使用属性与 ivars

特别是 Jens Alfke(前苹果员工)的回答:

  • 作为类的公共 API 的一部分。
  • 作为类实现中的抽象
  • 作为更改实例变量的便捷瓶颈——例如,如果您想在每次更改变量时触发其他内容,则将其设置为属性而不是直接写入 ivar 会很有用。
  • 在非 ARC 代码中,当您分配新值时,它可能是一种管理保留/释放舞蹈的便捷方式(但这个问题随着 ARC 而消失。)

我见过只为所有内部状态声明和使用属性的代码——我认为这是个坏主意。这真的很浪费 CPU 时间和代码大小,而且现在我们有了 ARC,它不再给你买任何东西了。

另外,请注意,除了 KVO 之外,还有其他性能问题。John McCall(现任 Apple 员工)表示:

属性以多种方式影响性能:

  1. 正如已经讨论过的,发送消息来执行加载/存储比仅执行加载/存储内联要慢。
  2. 发送消息进行加载/存储也需要在 i-cache 中保留更多代码:即使 getter/setter 除了加载/存储之外添加了零个额外指令,也会有一半- 调用者中的十几个额外指令来设置消息发送和处理结果。
  3. 发送消息会强制将该选择器的条目保留在方法缓存中,并且该内存通常保留在 d-cache 中。这会增加启动时间,增加应用程序的静态内存使用量,并使上下文切换更加痛苦。由于方法缓存特定于对象的动态类,因此在其上使用 KVO 的次数越多,这个问题就越严重。
  4. 发送消息会强制函数中的所有值溢出到堆栈中(或保存在被调用者保存寄存器中,这只是意味着在不同的时间溢出)。
  5. 发送消息可能会产生任意副作用,因此会强制编译器重置其关于非本地内存的所有假设。
  6. 消息发送可以有任意的副作用,因此不能被提升、沉没、重新排序、合并或消除。
  7. 在 ARC 中,消息发送的结果将始终由被调用者或调用者保留,即使是 +0 返回:即使该方法不保留/自动释放其结果,调用者也不知道并且有尝试采取措施防止结果自动释放。这永远无法消除,因为消息发送不是静态可分析的。
  8. 在 ARC 中,由于 setter 方法通常将其参数设为 +0,因此无法将该对象的保留(如上所述,ARC 通常具有)“转移”到 ivar,因此该值通常必须得到保留/释放两次。

当然,这并不意味着它们总是不好的——使用属性有很多好的理由。请记住,与许多其他语言功能一样,它们不是免费的。

除了 KVO,在设计应用程序时还要考虑这些。

于 2013-04-05T10:20:48.317 回答
2

这是否意味着 Xcode 生成的每个属性都实现了 willChangeValueForKey 和 didChangeValueForKey 方法?

不。除了属性不是由 Xcode 而是由编译器生成的事实之外,这意味着传统命名的属性在默认情况下是自动可观察的,并且您可以在需要时实现 KVO 方法这并不意味着每次设置属性时,都会调用跨类的各种方法。只有您指定的那些。

所以,基本上,不用担心这个。仅 KVO 不会对性能产生影响。

于 2013-04-05T10:15:26.970 回答
1

我认为这不会以任何方式影响性能。因此,如果您不想使用 KVO,可以忽略它。

addObserver仅当您用于观察 KV 变化时,观察才会开始并因此使用资源。

于 2013-04-05T10:14:26.577 回答
0

你可以看看+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key。它是一个类方法,而不是实例,它将配置一个类型的所有对象。

除了您的要求之外,这在您需要手动 KVO 而不是自动 KVO 时很有用。

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/#//apple_ref/occ/clm/NSObject/automaticallyNotifiesObserversForKey

于 2016-07-24T14:21:25.247 回答