Kristian Glass - Do I Smell Burning?

Mostly technical things

Objective-C and the Delegate pattern

Misunderstandings about delegates quite frequently come up on #iphonedev. This post should hopefully clarify a few things; arguably it doesn’t contain anything beyond that covered in the Apple docs, but hopefully presents it all in a more straightforward manner.

First, the basics. Everyone loves MVC right? The basic premise is that the View layer is dumb presentation, the Model is a straightforward data-store, and the Controller contains the logic, wiring and glue. Since most iPhone apps tend to be light on the Model-side, it’s common to combine the Model and Controller, but that’s just a common convenience.

So, you’ve got your view, and you want to add a button to, say, send you a “Button Pressed!” email. Now you could subclass your generic Button class and override the “buttonWasPressed” method, adding the “send email” code there. That doesn’t fly so well with MVC though, as now your View is doing Controller-type stuff. So, instead, you have the Button just forward things like “buttonWasPressed” on to another object, its delegate (a quick google for “define:delegate” gives “transfer power to someone” - pretty much!). Now your Button is free from pesky decisions like what to do when it’s pressed, it just passes on the message and lets its delegate (probably the Controller) handle it.

Now, here’s where we hear the question “Now I’ve got delegates, how do I deal with object ownership and such?”. This can also manifest itself as “My object’s delegate goes away and then my program crashes!” or “I have a retain cycle!”. There are some slight subtleties involved that frequently catch people out, but basically:

An object has no claim on its delegate

An object’s delegate is just something to which it sends messages, nothing more. Specifically, this means that it should NOT retain its delegate. Just in case that wasn’t clear, @property(retain) id delegate; should be taken out back and hit with a shovel until it agrees to stop retaining, and becomes a nice happy healthy assign property.

In almost every case, an object with a delegate will be the responsibility of its delegate, for example a UIViewController creating a UIButton, or a model object kicking off an asynchronous NSURLConnection. The delegating objects don’t want to lay claim to their delegates, they just want to message them. If they retained their delegates, cue the aforequestioned (I wonder if that’s a real word) retain cycle.

Along that line, it’s not the delegating object’s responsibility to deal with its delegate going away, but its creator/manager etc. So, if at init-time my FooObject creates a BarObject and sets itself as that BarObject’s delegate, it should set that BarObject’s delegate to nil in -[FooObject dealloc] prior to performing a [barObject release];. There’s lots of Foundation and UIKit code that uses delegation without explicitly using the word delegate, e.g. UIButton and NSURLConnection as mentioned above. In UIButton’s case, it’s unlikely that a Controller will go away before its View, thus clearing a UIButton’s targets can be ommitted; in NSURLConnection’s case, this is why -[NSURLConnection cancel] should be called at dealloc time, to ensure that the connection isn’t going to message its “delegate” after it goes away.

I hope that this has gone some way towards answering some of the common delegation queries, and that people find it useful. As ever, all input welcome.