Basics of Notifications

Sun, Apr 14

What follows is a brief guide to working with Notifications in Cocoa. I’ll cover the basics, including registering an observer and posting notifications, just enough to start using notifications in your apps.

There is an instance of NSNotificationCenter available to every running application. This class acts as an intermediary to facilitate communication between objects that are interested in being notified at some point in the future (these objects are known as the observers) and a poster that posts to the notification center, resulting in all observers (registered for a specific notification) being called.

To give you an idea of where you might use notifications, consider how you might handle downloading of data in a background thread. I recently used notifications in this scenario as I wanted to be notified when a web-service call completed. Upon receiving a notification, I then proceeded to populate a view with the data retrieved, or with an error message if the data access failed.

The 30,000 foot view consists of two steps:

Step #1
Register an observer, which requests that a selector to be called when a specific notification is posted.

Step #2
Post a notification, which will result in all registered observers being called.

For example:

1
2
3
4
// Register observer to be notified when download of data is complete
[[NSNotificationCenter defaultCenter] addObserver:self 
                                   selector:@selector(downloadDataComplete:) 
                                   name:NOTIF_DataComplete object:nil];

This code registers an observer for a notification with the name NOTIF_DataComplete (more on that below). When a notification is posted with the same name, the method downloadDataComplete will be called.

Posting a notification with the name NOTIF_DataComplete would look as follows:

1
2
3
// Post notification that the download is complete  
[[NSNotificationCenter defaultCenter] 
                    postNotificationName:NOTIF_DataComplete object:nil];

Let’s show how this might like in a working example.

Class Registering as Observer

1
2
3
4
5
6
7
8
9
10
11
12
13
//  SomeClass.h
 
#import <Foundation/Foundation.h>
 
@interface SomeClass : NSObject 
{
 
}
 
// For name of notification
extern NSString * const NOTIF_DataComplete;
 
@end

Below is the code for the implementation of SomeClass. Notice on line 6 the name of the notification is defined. On line 40 we register as an observer for the named notification, specifying the selector @selector(downloadDataComplete:). Once the notification is posted, the method on line 26 is called.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//  SomeClass.m
 
#import "SomeClass.h"
 
// Name of notification
NSString * const NOTIF_DataComplete = @"DataComplete";
 
#pragma mark -
#pragma mark Private Interface
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Private interface definitions
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@interface SomeClass (private)
- (void) dataDownloadComplete:(NSNotification *)notif;
@end
 
@implementation SomeClass
 
#pragma mark -
#pragma mark Private Methods
 
/*---------------------------------------------------------------------------
* Notifications of data downloads 
*--------------------------------------------------------------------------*/
- (void)downloadDataComplete:(NSNotification *)notif 
{
  NSLog(@"Received Notification - Data has been downloaded");
}
 
#pragma mark -
#pragma mark Initialization
 
/*---------------------------------------------------------------------------
* Initialization
*--------------------------------------------------------------------------*/
- (void) init
{
  // Other initialization code here...
 
  // Register observer to be called when download of data is complete
  [[NSNotificationCenter defaultCenter] addObserver:self 
                         selector:@selector(downloadDataComplete:) 
                         name:NOTIF_DataComplete object:nil]; 
 
}
 
#pragma mark -
#pragma mark Cleanup
 
/*---------------------------------------------------------------------------
* Cleanup 
*--------------------------------------------------------------------------*/ 
- (void)dealloc 
{
  [[NSNotificationCenter defaultCenter] removeObserver:self];
  [super dealloc];
}
 
@end

Class That Posts Notification

To keep things simple, I’ll add a few lines to the applicationDidFinishLaunching method to show you how posting a notification might look:

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)applicationDidFinishLaunching:(UIApplication *)application 
{
  [window makeKeyAndVisible];
 
  SomeClass *someclass = [[SomeClass alloc] init];
 
  // ...
 
  // Post a notification that the data has been downloaded  
  [[NSNotificationCenter defaultCenter] 
            postNotificationName:NOTIF_DataComplete object:nil];
 
}

I create an instance of SomeClass and follow this by posting of a notification of the name NOTIF_DataComplete. This example is a little contrived, however, I’m sure you get the idea. Although a short example, it shows just how easy it is to register an observer and post notifications.

There are various other nuances to working with notifications that can be quite helpful when the time comes that you need more robust support for communication among objects. For example, you could specify that you are interested in receiving a notification by name (as above), however, only if that notification has a specific object affiliated with it. This would allow you to use the same notification name, however, only notify certain objects. One use of this could be if you have multiple downloads and want to use notifications to be notify a specific object that it’s download is complete.

If you are working with multiple threads, which would be the case if you need to fire off multiple downloads in the background, you can look into distributed notifications, which allow notifications to be delivered to a particular thread.

6 comments

Thanks for the great post, John! I came across you blog trying to learn more about notifications.

You seem like you might be able to answer a question that I have (or at least point my research in the right direction).

I want to find out what iTunes events are exposed via notifications. Specifically, I’d like to write something to respond to a new movie rental in iTunes so that I can automate the exclusion of that rental file from Time Machine so that I don’t backup movies that will be useless after 24 hours have passed.

Do you know if such events exist? Are all iTunes events documented somewhere? Any ideas regarding a different way of achieving the same end?

Thanks!

by Joe W on Aug 30, 2009. Reply #

Nice explanation. All your posts are very simple to understand with a clear language. Congrats. I submit to your RSS to see the information you have to share on the future. Thank you.

by Paulo Oliveira on Oct 25, 2009. Reply #

Hey John,

Thanks for your publishing.

May I know Is it that the Notification is needed to define in the App Delegate?

What if I define it inside the NSObject ?

by Jacky on Apr 11, 2011. Reply #

Jacky, You can define the Notification in any class, I was using the App Delegate only as a simple example.

by john on Apr 11, 2011. Reply #

Thanks .. good tutorial

by Anonymous on Nov 7, 2011. Reply #

Nice post John.
I saw your post while searching for an example for Notifications with no idea about how to use it.
U gav clear idea with this simple post.
Thanks dude.

by Ram on Nov 14, 2011. Reply #

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>