About
This is the M Cubed Software weblog. To find out more about us head to our about page.
Search
Feed
Archives
- March 2010
- February 2010
- January 2010
- November 2009
- August 2009
- July 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
The Rules of Communication
Posted on 05/02/2010 at 10:28 PM in Coding
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.
Rule #1: Always use delegates for 1 to 1 relationships
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.
Rule #2: Use notifications for communicating events to many objects
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.
Rule #3: Use KVO for communicating data model changes
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.
Rule #4: Use blocks instead of callback delegates
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.
Rule #5: Comment anything that isn't clear
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.
Rule #6: If something seems like magic, learn how it works
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.
(4) Comments
Comments
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.
Posted by Patrick on 06/02/2010 at 08:08 PM
The best links are probably Apple’s docs on the subject:
Delegates: http://bit.ly/aSoBFS
Notifications: http://bit.ly/dp2KCy
KVO: http://bit.ly/aTcHzw
Posted by M Cubed on 07/02/2010 at 01:18 AM
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.)
Posted by Ben Cohen on 10/02/2010 at 02:44 PM
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