简体   繁体   English

在目标C中禁用键值观察

[英]Disable Key-Value Observing in Objective C

I don't use KVO, mostly for performance reasons, so I would like to make sure that I disable it properly. 我不使用KVO,主要是出于性能方面的考虑,因此我想确保正确禁用它。

From Apple Key-Value Observing Programming Guide 从Apple键值观察编程指南

Automatic support (for KVO) is provided by NSObject and is by default available for all properties of a class that are key-value coding compliant. NSObject提供了自动支持(针对KVO),默认情况下,自动支持可用于符合键值编码的类的所有属性。 Typically, if you follow standard Cocoa coding and naming conventions, you can use automatic change notifications—you don't have to write any additional code. 通常,如果您遵循标准的Cocoa编码和命名约定,则可以使用自动更改通知,而不必编写任何其他代码。

Is that mean that every property generated by Xcode has willChangeValueForKey and didChangeValueForKey methods implemented? 这是否意味着Xcode生成的每个属性都willChangeValueForKey实现willChangeValueForKeydidChangeValueForKey方法?

If so is there some way (some flag or something) to disable this behaviour? 如果是这样,是否有某种方法(某些标志或某物)来禁用此行为? I'm using accessInstanceVariablesDirectly and returning always NO, but I'm not sure if this is good enough. 我正在使用accessInstanceVariablesDirectly并始终返回NO,但是我不确定这是否足够好。

I don't use KVO. 我不使用KVO。

You cannot really know that. 你真的不知道。 Cocoa framework classes or other foreign code might depend on KVO without your knowledge. 在您不知情的情况下,可可框架类或其他外部代码可能依赖于KVO。

Also, NSObject's KVO uses a technique called isa-swizzling to automatically augment observed objects by dynamically subclassing them. 另外,NSObject的KVO使用称为isa-swizzling的技术通过动态子类化观察对象来自动增强它们。 That means that there's no overhead on objects that are not observed. 这意味着没有被观察到的对象没有任何开销。

Your other questions: 您的其他问题:

accessInstanceVariablesDirectly is used in KVC only, and is not connected to KVO. accessInstanceVariablesDirectly仅在KVC中使用,并且未连接到KVO。 There's no performance benefit in overriding it. 覆盖它没有性能优势。

Does that mean that every property generated by Xcode has willChangeValueForKey and didChangeValueForKey methods implemented? 这是否意味着Xcode生成的每个属性都实现了willChangeValueForKeydidChangeValueForKey方法?

Yes, every object responds to these methods. 是的,每个对象都对这些方法做出响应。 But the presence of these methods again does not mean that performance is affected in any way. 但是再次出现这些方法并不意味着性能会受到任何影响。 Usually the methods are not even called. 通常,这些方法甚至都不会被调用。

In short: 简而言之:

Usually, you use properties when accessing the object from the outside. 通常,从外部访问对象时使用属性。 Then, performance should not be critical since you are probably not performing heavy work. 然后,性能可能不会很关键,因为您可能不会执行繁重的工作。 If KVO is an issue, you probably need to review you application's design. 如果KVO是问题,则可能需要检查应用程序的设计。 From the object itself, it is better to access ivars directly, in which case KVO is irrelevant. 从对象本身开始,最好直接访问ivars,在这种情况下,KVO无关紧要。

More details: 更多细节:

This topic has been discussed recently on the apple mailing lists : 最近在苹果邮件列表上讨论了这个主题:
When to use properties vs. ivars 何时使用属性与ivars

In particular, there is the answer of Jens Alfke (former Apple employee): 特别是,Jens Alfke(Apple前雇员)的答案是:

  • As part of the class's public API. 作为类的公共API的一部分。
  • As an abstraction in the implementation of the class 作为类实现的抽象
  • As a convenient bottleneck for changing an instance variable — for instance, if you want to trigger something else every time you change the variable, it's useful to set it as a property instead of writing directly to the ivar. 作为更改实例变量的方便瓶颈,例如,如果您想在每次更改变量时触发其他操作,将其设置为属性而不是直接写入ivar很有用。
  • In non-ARC code it can be a convenient way to manage the retain/release dance when you assign a new value (but this issue goes away with ARC.) 在非ARC代码中,当您分配新值时,这可能是管理保留/释放操作的便捷方法(但是ARC消除了这个问题。)

I have seen code that just declares and uses properties for all internal state — I think that's a bad idea. 我见过只声明并使用所有内部状态的属性的代码-我认为这是一个坏主意。 It's really wasteful of both CPU time and code size, and it doesn't buy you anything anymore now that we have ARC. 这确实浪费了CPU时间和代码大小,而且现在有了ARC,它再也不会给您带来任何好处。

Also, note that there are other performance concerns than KVO. 另外,请注意,除KVO之外,还有其他性能问题。 John McCall (current Apple employee) states: John McCall(苹果公司现任员工)表示:

Properties affect performance in a lot of ways: 属性会以多种方式影响性能:

  1. As already discussed, sending a message to do a load/store is slower than just doing the load/store inline. 如前所述,发送消息以进行加载/存储比仅内联执行加载/存储要慢。
  2. Sending a message to do a load/store is also quite a bit more code that needs to be kept in i-cache: even if the getter/setter added zero extra instructions beyond just the load/store, there'd be a solid half-dozen extra instructions in the caller to set up the message send and handle the result. 发送消息以进行加载/存储也需要在i-cache中保存更多的代码:即使getter / setter除了加载/存储之外添加了零个额外的指令,也有相当一部分-调用方中的数十条额外指令来设置消息发送和处理结果。
  3. Sending a message forces an entry for that selector to be kept in the method cache, and that memory generally sticks around in d-cache. 发送消息会强制将该选择器的条目保留在方法缓存中,并且该内存通常会停留在d缓存中。 This increases launch time, increases the static memory usage of your app, and makes context switches more painful. 这会增加启动时间,增加应用程序的静态内存使用率,并使上下文切换更加痛苦。 Since the method cache is specific to the dynamic class for an object, this problem increases the more you use KVO on it. 由于方法高速缓存特定于对象的动态类,因此您对它使用KVO的次数越多,此问题就会增加。
  4. Sending a message forces all values in the function to be spilled to the stack (or kept in callee-save registers, which just means spilling at a different time). 发送消息会强制将函数中的所有值溢出到堆栈中(或保留在被调用者保存的寄存器中,这仅意味着在不同时间溢出)。
  5. Sending a message can have arbitrary side-effects and therefore forces the compiler to reset all of its assumptions about non-local memory. 发送消息可能会产生任意副作用,因此会强制编译器重置其对非本地内存的所有假设。
  6. A message send can have arbitrary side-effects and therefore cannot be hoisted, sunk, re-ordered, coalesced, or eliminated. 消息发送可能有任意副作用,因此不能被悬挂,下沉,重新排序,合并或消除。
  7. In ARC, the result of a message send will always get retained, either by the callee or the caller, even for +0 returns: even if the method doesn't retain/autorelease its result, the caller doesn't know that and has to try to take action to prevent the result from getting autoreleased. 在ARC中,即使+0返回,消息的发送结果也将始终被被调用方或调用方保留:即使该方法不保留/自动释放其结果,调用方也不知道并具有尝试采取措施以防止结果自动发布。 This can never be eliminated because message sends are not statically analyzable. 由于无法静态分析邮件发送,因此永远无法消除这种情况。
  8. In ARC, because a setter method generally takes its argument at +0, there is no way to "transfer" a retain of that object (which, as discussed above, ARC usually has) into the ivar, so the value generally has to get retain/released twice. 在ARC中,由于setter方法的参数通常为+0,因此无法将保留的对象(如上所述,ARC通常具有)“转移”到ivar中,因此通常必须获取该值保留/释放两次。

None of this means that they're always bad, of course — there are a lot of good reasons to use properties. 当然,这都不意味着它们总是不好的-使用属性有很多充分的理由。 Just keep in mind that, like many other language features, they're not free. 请记住,与许多其他语言功能一样,它们不是免费的。

Beyond KVO, these are to be taken into account when designing your application. 除KVO之外,在设计应用程序时还要考虑这些因素。

Is that mean that every property generated by Xcode has willChangeValueForKey and didChangeValueForKey methods implemented? 这是否意味着Xcode生成的每个属性都将实现willChangeValueForKey和didChangeValueForKey方法?

No. Apart from the fact that the properties are not generated by Xcode but by the compiler, this rather means that conventionally-named properties are automatically observable by default and you can implement KVO methods if you need them. 不。除了属性不是由Xcode而是由编译器生成的事实外,这还意味着默认情况下可以自动观察常规命名的属性,并且可以 在需要时实现KVO方法 It doesn't mean that every time you set a property, all sorts of methods across the classes will be called. 这并不意味着每次您设置属性时,将调用类中的各种方法。 Only the ones you specify. 仅您指定的。

So, basically, don't worry about this. 因此,基本上,不必为此担心。 There's no performance impact introduced merely by KVO. KVO不会对性能产生任何影响。

I do not think that this will in any way impact performance. 我认为这不会以任何方式影响性能。 Therefore you can just ignore KVO if you do not want to use it. 因此,如果您不想使用KVO,则可以忽略它。

The observing will only start and thus use resources when you use addObserver to observe a KV change. 仅当使用addObserver观察KV更改时,观察才会开始,因此将使用资源。

You may have a look at + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key . 您可以看看+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key It's a class method, not instance, and will configure all objects of a type. 这是一个类方法,而不是实例,它将配置类型的所有对象。

Apart from your requirement, this is useful when you need manual KVO instead of the automatic KVO. 除了您的要求之外,当您需要手动KVO而不是自动KVO时,这很有用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM