Peter Steinberger

Don't Call willChangeValueForKey Unless It's Really Needed

You’re using KVO, right? So you most likely have already written code like this:

Carefully encapsulate your calls within a call to willChangeValueForKey/didChangeValueForKey to “enable” KVO. Well, turns out, you just did shit work. There’s no reason to do the will/did dance, as long as you are using a setter method to change the ivar. It doesn’t need to be backed by an ivar or declared as a property. KVO was written long before there was anything like @property in Objective-C.

In fact, I have been writing iOS apps for about four years and didn’t know this. A lot of open-source code also gets this wrong. Apple has some good KVO documentation, where it explains the concept of automatic change notifications.

There is a reason why you want to manually add willChangeValueForKey: most likely changing a variable also affects other variables. The most popular example is NSOperation:

Sometimes you might also want to optimize how often you’re sending KVO notifications with overriding automaticallyNotifiesObserversForKey: to disable automatic change notifications for certain properties.

In this example, there might be expensive KVO observations when the image changes, so we want to make damn sure that KVO is only fired if the image actually is a different one than the image that is already set:

If you currently have such obsolete calls, they’re not doing any harm. Incrementally called, willChangeValueForKey doesn’t emit more notifications. Still, time to delete some code!

Update: Don’t forget that there are more ways that’ll save you manual calls to will/did, like using the little-known addition keyPathsForValuesAffecting(PropertyName), which utilizes some runtime magic to make KVO smarter. Here’s a real-life example of how I used that on AFNetworking, so people can register a KVO notification on “isNetworkActivityIndicatorVisible” and it’ll get sent every time activityCount is changed. (You’ll also see that I do some atomic updating that requires manual KVO.)