In iOS 4, Apple introduced a new way to send “push notifications” to your app without having a dedicated server and associated server side coding. The technique is called as scheduling local notifications. While this tutorial is about how to schedule local notifications, I would also explain how a powerful abstraction concept, Singleton design pattern could make this easier when adding local notification support to your app.

If you were following my blog, you might have already read about the singleton xcode template I wrote about previously. If not, go ahead and download the Singleton class template. Install it into your xcode installation folder (which is normally /Developer). Come back here.

Let’s get started.

Step 1:

Create a view based application. (Or any application type you prefer)

Step 2:

Add a Singleton class using my template and call it, say, MKLocalNotificationsScheduler

Step 3:

Within the sharedInstance static method (which is the constructor), add the following lines of code

// iOS 4 compatibility check
Class notificationClass = NSClassFromString(@"UILocalNotification");
if(notificationClass == nil)
_instance = nil;
_instance = [[super allocWithZone:NULL] init];
_instance.badgeCount = 0;

This class is the singleton method’s sole constructor. This sharedInstance is accessed your view or any other class that requires this class’s object.

In this class we write code for checking if UILocalNotification class is available. Remember that it’s available only on iOS 4 and above. The “constructor” intelligently allocates a instance of itself only when it runs on iOS 4. Otherwise the shared instance is always nil.

You should by now appreciate the power of singleton and it’s design elegance. Do note that, because we are going to channel the complete notification mechanism of the application through this single class, we can maintain the application icon’s badge count as a instance variable.

Step 4:

Now, lets write the real meat.

Scheduling a local notification is far easier compared to push notifications. Just allocate a instance of a UILocalNotification and fill in the necessary parameters and submit it to the applications’ shared instance.

In our singleton instance, we will create a helper method that automatically creates a local notification object, fills it with default values properly and schedules it. The helper also takes care of incrementing the badgeCount, thereby maintaining its state.

- (void) scheduleNotificationOn:(NSDate*) fireDate
								text:(NSString*) alertText
								action:(NSString*) alertAction
								 sound:(NSString*) soundfileName
						   launchImage:(NSString*) launchImage
							   andInfo:(NSDictionary*) userInfo
	UILocalNotification *localNotification = [[UILocalNotification alloc] init];
    localNotification.fireDate = fireDate;
    localNotification.timeZone = [NSTimeZone defaultTimeZone];	
    localNotification.alertBody = alertText;
    localNotification.alertAction = alertAction;	
	if(soundfileName == nil)
		localNotification.soundName = UILocalNotificationDefaultSoundName;
		localNotification.soundName = soundfileName;
	localNotification.alertLaunchImage = launchImage;
	self.badgeCount ++;
    localNotification.applicationIconBadgeNumber = self.badgeCount;
    localNotification.userInfo = userInfo;
	// Schedule it with the app
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    [localNotification release];

Step 5:

Now, to test this, un-comment the viewDidLoad method from the view controller generated by XCode. Add the following line

[[MKLocalNotificationsScheduler sharedInstance] scheduleNotificationOn:[NSDate dateWithTimeIntervalSinceNow:20]
text:@"Hey there"

Note that, except the fireDate, all other parameters can be nil and the helper automatically fills in the default values. As such your calling code is just a one liner.

Step 6:

Now, when a local notification arrives, the operating system, notifies you through two different channels. One is the

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

method and the other is

- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)localNotification;

A better design guideline would be to pass this localNotification object to our Singleton class as that Singleton class is the one that “best knows” what to do with the notification payload.

UILocalNotification *localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification) 
    [[MKLocalNotificationsScheduler sharedInstance] handleReceivedNotification:localNotification];

Step 7:
Write a function within our Singleton to handle the notification payload. In our case, we just NSLog the notification description and reduce the badge count. You can add your app-specific sophisticated logic here.

- (void) handleReceivedNotification:(UILocalNotification*) thisNotification
	NSLog(@"Received: %@",[thisNotification description]);
	[self decreaseBadgeCountBy:1];

Also write other miscellaneous helper methods that handle badge count

- (void) clearBadgeCount
	self.badgeCount = 0;
	[UIApplication sharedApplication].applicationIconBadgeNumber = self.badgeCount;
- (void) decreaseBadgeCountBy:(int) count
	self.badgeCount -= count;
	if(self.badgeCount < 0) self.badgeCount == 0;
	[UIApplication sharedApplication].applicationIconBadgeNumber = self.badgeCount;

Now run the app on simulator or device. Note that unlike, push notifications, local notifications work on simulator. Since we schedule a local notification after 20 sec, close the app by clicking the home button on the simulator (or device) and wait. You should see a alert box like this.

Source Code:

The complete source code is available at Github. Feel free to tinker with the code and mainly, if you fork it, and want me to have a look, do drop me a message or leave a comment here.

That’s it for this tutorial. Happy coding (and designing).


Follow me on Twitter