14 Jun 2011 When to use Delegation, Notification, or Observation in iOS
A common problem that we often experience when developing iOS applications, is how to allow communication between our controllers, without the need to have excessive coupling. Three common patterns that appear time and time again throughout iOS applications include:
- Notifications through Notification Center, and
- Key value observing
So why do we need these patterns and when should and shouldn’t they be used?
The following discussion of the three patterns are purely from my own experiences of developing iOS applications. I’d like to discuss why I feel a particular pattern is better than another and why I believe certain patterns are better in certain circumstances. The reasons I give are not gospel, and are just my personal opinions. Please feel free to argue and provide me with reasons and experiences you’ve had.
What is it about these three patterns?
The three patterns chosen are all ways for one object to communicate events to other objects without requiring them to be coupled. They are ways for objects to “inform” the occurrence of certain events, or more accurately, ways to allow certain events to be heard by others. This is quite a common task for objects to have to do, as without communication, controllers cannot integrate into the application. Another goal of a controller however, is to be as self contained as possible. We want our controllers to be able to exist on their own, without coupling them to any other controllers above them in our controller hierarchy. Controllers can create other controllers and communicate freely with them, but what we don’t want is controllers being tied back up to their creator. If we do couple them, then we lose their ability to be reused and lose their ability to completely control an isolated component of our application.
The three patterns all provide ways for controllers (or other objects) to communicate and be useful within an application, without the need to couple them and lose their self-containment. Whilst I’ll be describing the patterns and their use in an iOS application context, it is important to note that they do exist and are used elsewhere. The comments I make may or may not apply to their use in other contexts.
When you first start out programming iOS application, you’ll most likely notice the continued use of “delegates” throughout the SDK. The delegation pattern is not a pattern specific to iOS, but depending on what programming background you’ve had, it might not be immediately obvious as to what advantages this pattern provides, and why it seems to be used so often.
The basic idea of delegation, is that a controller defines a protocol (a set of method definitions) that describe what a delegate object must do in order to be allowed to respond to a controller’s events. The protocol is a contract where the delegator says “If you want to be my delegate, then you must implement these methods”. What this does is allows the controller to call methods on it’s delegate with the knowledge that the delegate will respond to the method calls. The delegate can be of any object type, so the controller is not coupled to a particular Object, but it can still be sure that the delegate will respond when it tries to tell it things.
- Very strict syntax. All events to be heard are clearly defined in the delegate protocol.
- Compile time Warnings / Errors if a method is not implemented as it should be by a delegate.
- Protocol defined within the scope of the controller only.
- Very traceable, and easy to identify flow of control within an application.
- Ability to have multiple protocols defined by one controller, each with different delegates.
- No third party object required to maintain / monitor the communication process.
- Ability to receive a returned value from a called protocol method. This means that a delegate can help provide information back to a controller.
- Many lines of code required to define: 1. the protocol definition, 2. the delegate property in the controller, and 3. the implementation of the delegate method definitions within the delegate itself.
- Need to be careful to correctly set delegates to nil on object deallocation, failure to do so can cause memory crashes by calling methods on deallocated objects.
- Although possible, it can be difficult and the pattern does not really lend itself to have multiple delegates of the same protocol in a controller (telling multiple objects about the same event)
In iOS applications there is a concept of a “Notification Center”. It is a singleton object that allows for objects to be notified of events occurring. It allows us to satisfy the goal of communicating between a controller and an arbitrary object with a low level of coupling. The basic concept of this pattern is that a controller uses a key (notification name) in order to allow other objects to hear about special events occurring within the controller. Then unbeknown to the controller, other objects (observers) can react to the notification events by registering for notifications with the same key.
- Easy to implement, with not many lines of code.
- Can easily have multiple objects reacting to the same notification being posted.
- Controller can pass in a context (dictionary) object with custom information (userInfo) related to the notification being posted.
- No compile time to checks to ensure that notifications are correctly handled by observers.
- Required to un-register with the notification center if your previously registered object is deallocated.
- Not very traceable. Attempting to debug issues related to application flow and control can be very difficult.
- Third party object required to manage the link between controllers and observer objects.
- Notification Names, and UserInfo dictionary keys need to be known by both the observers and the controllers. If these are not defined in a common place, they can very easily become out of sync.
- No ability for the controller to get any information back from an observer after a notification is posted.
Key value observing (KVO) is a pattern in which one object can observe the value of another object’s properties to find out about changes. Where the previous two patterns (delegation and notifications) are more suited to a controller communicating with arbitrary objects, KVO is more suited to objects of any type listening for changes of another arbitrary object (not necessarily, and most often not a controller). It is a way in which we can keep our objects in sync with one another; a way in which we can make one object react when another object’s state changes. It is only used for properties and cannot be used to respond to methods or other actions.
- Can provide an easy way to sync information between two objects. For example, a model and a view.
- Allows us to respond to state changes inside objects that we did not create, and don’t have access to alter the implementations of (SKD objects).
- Can provide us with the new value and previous value of the property we are observing.
- Can use key paths to observe properties, thus nested objects can be observed.
- Complete abstraction of the object being observed, as it does not need any extra code to allow it to be observed.
- The properties we wish to observe, must be defined using strings. Thus no compile time warnings or checking occurs.
- Re-factoring of properties can leave our observation code no longer working.
- Complex “IF” statements required if an object is observing multiple values. This is because all observation code is directed through a single method.
- Need to remove the observer when it is deallocated.
Summing up the options
With these three patterns providing both pros and cons, how do we aggregate and sum these up in order to influence which pattern to use in which situation. There is no right or wrong pattern to use. Each pattern provides a way for objects to inform other objects of events, without the need for the informer to know about the listener. Of these three patterns I think Key Value Observing has the clearest use case, and has a clear suitability to a specific requirement. The other two patterns however have very similar uses, and are often used to provide communication between controllers. So which of these two should be use when?
In my personal experience of making iOS applications, I have often seen an excessive use of the Notification pattern. I personally very much dislike using the notification center. I find it is just too hard to follow the flow of your application. Keys for the UserInfo dictionaries passed around become out of sync, and too many constants need to be defined and placed in a common place. It is very hard for developers who start work on an existing project to understand the flow of an application when the notification center is used excessively.
I believe that communication between controllers should be made very clear through the use of well named protocols and well named protocol method definitions. Making the effort to define these protocol methods will yield much easier code to read, and provide much more traceability within your app. Changes to delegate protocols and implementations will be picked up by the compiler, and if not (EG if you are using selectors) your app will at least crash during development, rather than just having things not working properly. Even in scenarios where multiple controllers need to be informed of the same event, as long as your application is well structured in a controller hierarchy, messages can be passed up the hierarchy where they can be passed back down to all controllers that need to know of the events.
Of course there are exceptions where the delegation pattern just does not fit and notifications make more sense. An example might be an event that every controller in your application needs to know of. However these types of scenarios are very rare. Another example might be in scenarios whereby you are building a framework that needs to announce events to the application it is running in.
As a rule of thumb I will only use observation, for property level events within objects that I did not code, or for property level events within model objects that are tightly bound to a view object. For all other events, I will always try to use a delegate pattern, if for some reason I can’t do that, I will first assess whether I have something critically wrong with my app’s structure, and if not, only then will I use notifications.
Adam GerbertPosted at 01:14h, 23 June
One major thing I think you’ve missed is blocks. Many times this can be simpler than using a delegate, as state can be captured within each block preventing the need to maintain/pass around some “context” (like say, how the UIView animation delegate stuff works). They also are easier to trace as they can be read be read “top to bottom”, which can be extremely helpful when working with, for example, remote services:
– search: (NSString*) searchTerms
[searchWebService search: searchTerms
//this is executed ‘later’, but ti certainly _looks_ synchronous
//making it easier to follow code flow. It also doesn’t require all the
//ugly code overhead of defining a protocol etc leading to even less coupling.
There’s great documentation on their use on Apples developer library site titled “Blocks Programming Topics”
Adam GerbertPosted at 01:16h, 23 June
I just wanted to add that there certainly are cons to using blocks, one of which is memory management issues can become a bit more confusing than usual. The blocks programming topic goes into detail about how that all works and is definitely required reading if you’re going to use this great new feature.
Shaun ErvinePosted at 14:12h, 27 June
Just watched the WWDC 2011 Session video 112 – Writing easy to change code in which they talk about the maintainability side of notifications, especially when your trying to fix a bug. With notifications its really hard to keep track of who is observing events … compare that to a protocol / delegate approach when debugging code or reading it especially you can see who is calling what and when.
Like Adam mentioned this can be achieved with blocks as well because there is at least a level of coupling that is easy to follow.
Notifications can be used easily and are extremely powerful … but they do come with a price which is decoupling your code. It may not seem it now but in 6 months time your code may not be all that clear or obvious as to what exactly is going on.
ArunPosted at 23:53h, 17 November
I ‘m trying to access a single method at three times in a row from separate class. Each time i will be passing different parameter (parameters are the url which has to get connected to some webservice and retrieve the data) to the method so that i thought i can get three response for each calling. But for the sake of multithreading my second message get passed to the class before first one goes off , the same happening on third call. can gimme a quick guidance…
Thanks in advance
Hari Karam SinghPosted at 01:14h, 09 December
I often find myself wishing for a multi-delegate pattern. In fact, when I first started learning Coca, I couldn’t understand why it lacked the paradigm which is so common in other languages such as ActionScript 3 where you have an “addObserver” or “addListener” method, which allows you the benefit of protocol based type checking but with the flexibility of multiple listeners like NSNotifications.
Max GoldsteinPosted at 01:11h, 29 December
I’m teaching myself to develop apps and stumbled over this post. I just wanted to say thank you, it was very helpful.
SanderPosted at 22:24h, 18 January
Great article! As Adam already stated, blocks are a great alternative to event delegation (when used properly) and must not be overlooked.
GaryHPosted at 14:54h, 20 February
Yeah, this really helps. I’ve been through various books and every time i think about delegation, i get a bit confused. I’ve got a situation where three different view controllers each pull values from different databases, and each uses the same tableviewcontroller class to display the resulting values. The table segues to a detail view when a cell is selected. The user can delete a record in the detail view (which does make sense from UI perspective for this app).
So if the user deletes a record in the detail view, the table needs to update itself when it reappears (after the detail view closes itself).
I’m struggling to get clear on how the delegation pattern for this should work. Any advice appreciated.
GaryHPosted at 17:05h, 20 February
Actually, i figured this out after reading this and then reading something else on stack overflow. I added a protocol to my detail and had the table become its delegate. When the delete happened, the detail controller sent a message to the delegate tableview, which removed the object from its table and reloaded its data. And now it finally all makes sense. Whew!
Oliver FogginPosted at 22:46h, 19 April
Great article. I learnt about NSNotificationCenter last year and at first used it everywhere (well, not quite everywhere but you get the idea). This was when I was young and naive and didn’t fully grasp the use cases for KVO and delegation.
I’ve slowly begin to realise the down side of this. I’ve since switched about 90% of these uses to use delegation and flow (and performance) is vastly improved! One thing I’m really proud of is the use of delegates from a class that exclusively runs on a background thread with GCD. The delegate methods get run on the main thread by the background class and so I can just use the class as normal but everything runs multi threaded 😀
I also have a very strict MVC model in my app and (having read this article) I’m pleased to say I’ve used KVO perfectly from the model to the view 😀 It makes updating the view soooo much easier as it means I actually don’t have to update the view 😀
There are a couple more uses of NSNotificationCenter in my app and I am almost certain that I’ll be able to remove these too.
Derek ClarksonPosted at 10:19h, 07 May
I just read through it and my thoughts run slightly differently. I agree with your pros and cons, but I also think that the context is the decider.
KVO – where I need to track a property on a instance.
Delegates – Where I need to both be told when things occur and also provide functionality back to the caller. The table view delegates are good examples of this “Two-way” flow. I see delegates as a combination of the state/strategy patterns. There is also a scope aspect here because I think that generally speaking, only a single delegate is created and it generally lives for the same duration as the instance it is a delegate for. So once set, the instance can always assume it will be present. I’ve seen some very chaotic code where this rule was broken and they tried to swap delegates in and out as program state changed – chaos and Zombies.
NSNotifications – Where I want to broadcast the occurrence of some event, and don’t need to know anything about who is waiting for it or indeed, if anyone is. This is why I see it quite often used in the SDK for situations where longer term functionality is executing which most of the time, we don’t care about. I think that there is also a difference between this and delegates in that generally speaking, classes manage their own monitoring of notifications where as delegate management is often performed external to both the instance and it’s delegate.
yetanotherjoshPosted at 07:55h, 12 June
One thing that’s really worth pointing out as well is that, among those three patterns, there are very significant differences between *when* the callback (message, notification, etc) is fired. For delegates, you have the most control: the callback is fired precisely when your code decides to call the delegate, and synchronously, in the same runloop, on the same thread, unless you explicitly do something otherwise. For KVO, the callback is fired synchronously when the *setter method* completes, which can be a source of bugs if the setter method does not handle 100% of the expected state change that the observer is depending on. Also with KVO, the callback is fired on the thread that changed the property, which may or may not be the desired thread for the observer process. With NSNotificationCenter, the delivery time of your notification is delayed by at least a run loop, which can be a severe problem. For instance, it is NOT safe to use an NSNotification to bind changes to a model class that is a UITableViewDataSource to a UIViewController that manages the tableview reloading – your data state can change before the view gets the update signal, causing a crash due to an inconsistent expectation of, say, the number of rows in the table to the actual number of rows in the data source. For these reasons I strongly prefer the delegate pattern unless the situation strongly warrants otherwise.
SatanPosted at 21:28h, 08 October
Didn’t see any document said the NSNotificationCenter post notification at a runloop later. Can you provide some useful links?
SatanPosted at 21:31h, 08 October
I think You are wrong about NSNotificationCenter. The delivery time is in the same run loop
David CarricoPosted at 09:56h, 21 October
Nice comparison, very helpful. Thank you for posting it.
RayPosted at 22:25h, 17 December
Useful info. Thanks all.
I have a question about connecting AppDelegates and MasterViewController when using storyboards. In the latest version of Xcode, when you create a basic project, the default template has no connection between the AppDelegate and the MasterViewController. My app will (both based on user input and pre-fetching the next record) fetch & parse XML.
It seems that the best place to kick-off the initial data fetch is in AppDelegate, because the next view that’s loaded depends on the data that’s loaded. But if I go that route, then the only way I see to let the MasterViewController know that the data has been downloaded and parsed is via a Notification.
Would this be an OK time to use Notifications? Especially since there will likely be a time when multiple objects will need to know that new data has been loaded.
Alternately, I could add a way for AppDelegate to message MasterViewController, but I suspect there’s a good reason Apple separated the two items when using Storyboards.
And then the third option would be to move the code that kicks-off the download, parsing, error notifications, etc. into the MasterViewController, but based on the sample apps from Apple, it seems that I have the communication with the downloader and parser in the right spot.
CarlosPosted at 10:53h, 05 January
This post is really helpful to understand a little more how we can get a better performance/reusability of our code. It would be awesome if you can mix these great tips with a piece of code for each one. I know that there are several examples around the web but there I have’t found a complete post mixing “theory + code”…Thanks in advance!!
Andrei MereutaPosted at 00:41h, 27 May
I have resolved the problem of delegation with multiple delegate with the folowing code:
NSPointerArray *delegates = [[NSPointerArray alloc]initWithOptions:NSPointerFunctionsWeakMemory];
for (id delegate in _delegates.allObjects)
if ([delegate respondsToSelector:@selector(SomethingChangedToDelegateWithObject:)])
[_delegates addPointer:(__bridge void *)(delegate)];
What do you think about my aproach on this matter. Personaly i like using just the delegation aproach.
Pingback:自定义NSNotification消息中心 | 神刀安全网Posted at 02:15h, 20 June
[…] Pattern可以分为三种：delegate，NSNotification，KVO， 这里详细介绍了这三种方式的区别 […]
Pingback:Examples of Delegates in Swift - iZZiSwiftPosted at 18:13h, 10 November
[…] When to Use Delegation, Notification, or Observation in iOS. […]