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;
}
else
{
_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;
	}
	else
	{
		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"
action:@"View"
sound:nil
launchImage:nil
andInfo:nil];

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).


Mugunth


Follow me on Twitter

  • vivek

    Hey MK , ( Hand shake) , Nice tutorial , Any plan to put something on ebook/page flip programming ?

    Thanks

  • Arild

    Thanks for a nice tutorial!

    Just found your blog and what I have read so far is very good and informative!

  • Marciokoko

    Ok so I take it this is only for local events, residing on your device? If I need an app to be notified of a cloud-based db posting, it needs to be via notifications?

  • http://twitter.com/chiragvaghela31 Chirag Vaghela

    Hey MK , ( Hand shake) , Nice tutorial , But i set more than 64 notification it’s not working properly

    • Anonymous

      The limit is 64 local notifications. Please take a look at the API documentation.

  • List Master

    if(self.badgeCount < 0) self.badgeCount == 0;is incorrect. should be if(self.badgeCount < 0) self.badgeCount = 0;

  • List Master

    if(self.badgeCount < 0) self.badgeCount == 0;is incorrect. should be if(self.badgeCount < 0) self.badgeCount = 0;

  • List Master

    if(self.badgeCount < 0) self.badgeCount == 0;is incorrect. should be if(self.badgeCount < 0) self.badgeCount = 0;

  • List Master

    if(self.badgeCount < 0) self.badgeCount == 0;is incorrect. should be if(self.badgeCount < 0) self.badgeCount = 0;

  • Cmaldonados

    Nice tutorial… could you think of any reason as why, when I’m in home and notification alert shows up, after I click on View button, execution doesn’t go to -(BOOL)application:didFinishLaunchingWithOptions: method?

  • Peter Fehrman

    Absolutely great class!

    But how do I handle the AlertView if the user clicks on “read more” for example? Then I want to launch the app and push a certain ViewController.

  • http://www.muhammadnawaz.bravehost.com/ Nawaz

    good one :)

  • Mills

    Nice Tutorial :)
    But i need more on this.I want to set ringtone from device as in Normal Alarm works.I can set SoundName as default but how to set it to ringtones from device?I searched everything but it says to create a alarm like functionality in uilocalnotification you need to drag those tone in your proj bundle,but i think its not the way to set alarm and second is,we can use music lib of iOS but it also has limitations of 30secs so we cant select a song there and also uilocalnotification displays Alert window first and then on clicking ‘Launch’ takes us our proj…
    Please help me to set customized alarm in app as in system alarm ….

    Thanks in advance..

  • prasad kumar

    Nice tutorial..

    NSString *activityTime=@”2012-12-23 05:00 PM”;

    UILocalNotification *mlocalNotif1 = [[UILocalNotification alloc] init];

    mlocalNotif1.soundName = UILocalNotificationDefaultSoundName;

    mlocalNotif1.timeZone = [NSTimeZone defaultTimeZone];

    mlocalNotif1.applicationIconBadgeNumber = mlocalNotif1.applicationIconBadgeNumber+1;

    mlocalNotif1.alertAction = @”View”;

    [mlocalNotif1 setHasAction:YES];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

    [dateFormatter setDateFormat:@"yyyy-MM-dd hh:mm aa"];

    mlocalNotif1.fireDate= [dateFormatter dateFromString: activityTime];

    mlocalNotif1.alertBody =@” This your reminder for dance”;

    [mlocalNotif1 setRepeatInterval:NSDayCalendarUnit];

    [[UIApplication sharedApplication] scheduleLocalNotification:mlocalNotif1];

    Is it possible to show notifications On Specific dates

    I had Code For Showing Local Notification For Specific Date,How to Call the notification For three Specific Dates With Single Notification Code.

    For Example:2/5/2012,6/5/2012,8/5/2012 I want Notification for All These 3 days at Specific Time.

    So Let me Know if it Is possible

  • Kemal Serkan YILDIRIM

    How to make multiple local notification with your sample.

    Adding this code how many do I want;

    [[MKLocalNotificationsScheduler sharedInstance] scheduleNotificationOn:[NSDate dateWithTimeIntervalSinceNow:20]

    text:@”Hey there”

    action:@”View”

    sound:nil

    launchImage:nil

    andInfo:nil];

  • jagdish

    Will it work on Simulator, because i tried with but is not working. Any idea why is that so?

  • Pingback: Do I need Push-Notification to remind the user of something - Xcode Solutions - Developers Q & A