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:
- As already discussed, sending a message to do a load/store is slower
than just doing the load/store inline.
- 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.
- 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.
- 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).
- Sending a message can have arbitrary side-effects and therefore forces the compiler to reset all of its assumptions about non-local
memory.
- A message send can have arbitrary side-effects and therefore cannot be hoisted, sunk, re-ordered, coalesced, or eliminated.
- 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.
- 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.