At NSConference Dave Dribin made the following statement in a slide:
Delegates are preferable to Notifications which are preferable to KVO
Now this caused a bit of a murmur on Twitter, as it was taken as "KVO is bad". As this is an important topic and not one that can easily fit into 140 characters I thought I would write a post to outline my rules for when to use each technology and why use them where I do.
One of the main reasons delegates were listed as the most preferable is that they provide the least 'magic' way of communicating between objects while keeping them loosely coupled. It sends the message directly to the object and you can see what method is being run. As such it makes your code more self explanatory. So whenever you have a 1 to 1 relationship between two classes, opt for delegation over notification.
Notifications should really be used wherever you would use a delegate, but need to communicate with any number of objects. They should really be thought of as 1 to many delegates. Quite often in Cocoa you will see a case where there is a notification and a delegate method for the same event (eg change of selection in a table view). These are cases where 80% of the time you just need a 1 to 1 relationship, but occasionally do need a 1 to many relationship. You will rarely encounter this in your own code, unless you are building a class for use in multiple apps.
This is where I have found KVO to be the most powerful. You need to keep various UI elements in sync with your data model. Changing the value of the model from one view should also update the value in other views. KVO was built for exactly this situation and as such requires much less code than delegation and notifications.
To achieve the same effect with delegation or notifications you would have to add delegate methods or post a notification in each setter method of each model object. This obviously is a lot of code that needs to be written. Code that could have bugs and code that makes your source more cluttered. KVO of a value in an object requires just one line of code and the implementation of one method. And if you use bindings then it is actually no code at all.
I'll start with the exception to this: if you have multiple callback options then use delegates (eg NSURLConnection). But the vast majority of asynchronous operations need just a single callback. In these cases, if you are using Mac OS X 10.6, then you should be using blocks instead of delegates. Blocks reduce the layer of indirection in your source by putting the call back information inline with the invocation of the method.
The next two rules aren't quite rules of communication, but are relevant to the discussion at hand.
This should be pretty obvious. If something in your code isn't explicitly clear from the code itself then comment it. If you are sending off a notification say why you are sending it off, so you can get an idea of what it is doing elsewhere in the application.
There is no such thing as magic in programming, simply things we don't fully understand. If notifications, delegation, KVO or anything else seems like magic, then read up the documentation on it or ask a developer experienced in that area to explain how it works. When you find out how they work you realise that what seems like magic is fundamentally a very simple process.
Ultimately, what Dave said was right for some scenarios. Each technology has its use case and you should only use it where it is needed. You should always aim for the smallest amount of indirection in your code while still retaining loose coupling of classes. KVO and notifications are necessary in some occasions (unless you want to go crazy with delegation) but they should only be used when they are needed.
Thanks for the very clear overview of when to do what.
Do you have some quick pointers/links to “read up the documentation” for these three techniques? Thanks.
The best links are probably Apple’s docs on the subject:
I’ve been working with the Cocoa-HTTP project. The HTTP_Server object creates many instances of a connection class. I use notifications as the medium for communicating from the connection objects to the app delegate (for example when a connection receives a POST request).
I would describe this as the inverse of rule 2, i.e. many to one communication.
(I suppose the server object could call the app delegate when it creates a new connection, thus allowing the app delegate to configure each connection object for one-to-one communication but that seems like a lot of code for little benefit.)
In that case I would probably use a delegate myself. A many to one is essentially many one to one relationships. The changes would be relatively minor:
- Remove line adding app delegate as observer
- Add delegate ivar and property to HTTP_Server object
- When creating HTTP_Server object add the line [server setDelegate:self];
- Instead of posting a notification, check if the delegate responds to the selector and then call the method on the delegate
There isn’t much difference in what it does conceptually, but theoretically delegation should be slightly faster