2
votes

I don't use KVO, mostly for performance reasons, so I would like to make sure that I disable it properly.

From Apple Key-Value Observing Programming Guide

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. 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.

Is that mean that every property generated by Xcode has willChangeValueForKey and didChangeValueForKey methods implemented?

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.

5
Have you profiled to determine that this is a problem? If not then your question is pointless.borrrden
How could I profile it? Compare normal property usage to what exactly? Maybe for you it's pointless but I like to know how exactly programming language that I use works.Martin
Instruments would show a high CPU cycle usage in calls to your properties (since KVO calls are performed syncronously) if KVO were to be taking too much time. Saying that you want to disable KVO for performance reasons for any other reason is premature optimization.borrrden

5 Answers

10
votes

I don't use KVO.

You cannot really know that. Cocoa framework classes or other foreign code might depend on KVO without your knowledge.

Also, NSObject's KVO uses a technique called isa-swizzling to automatically augment observed objects by dynamically subclassing them. 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. There's no performance benefit in overriding it.

Does that mean that every property generated by Xcode has willChangeValueForKey and didChangeValueForKey methods implemented?

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.

3
votes

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. From the object itself, it is better to access ivars directly, in which case KVO is irrelevant.

More details:

This topic has been discussed recently on the apple mailing lists :
When to use properties vs. ivars

In particular, there is the answer of Jens Alfke (former Apple employee):

  • As part of the class’s public 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.
  • 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.)

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.

Also, note that there are other performance concerns than KVO. John McCall (current Apple employee) states:

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.
  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. 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.
  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. 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.

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.

2
votes

Is that mean that every property generated by Xcode has willChangeValueForKey and didChangeValueForKey methods implemented?

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. 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.

1
votes

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.

The observing will only start and thus use resources when you use addObserver to observe a KV change.

0
votes

You may have a look at + (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.

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