This solution is great and all, but it still requires that you have an active internet connection. As of iOS4, Apple has introduced a new type of notification that can be scheduled to fire within the device itself. It requires no complicated server programming, or additional configuration with iTunes. I am talking about Local Notifications.
Local notifications can be scheduled on the user’s iDevice to fire at any given time; you can even set them to be recurring. Today, we will explore these notifications and I will provide you with a simple example of how to schedule, view, and handle local notifications. Here is a quick screenshot of the project that we are going to create (note I am using the iPhone 4 simulator).
1. Create a View-Based Application
We will be using this as our starting point. Check out this tutorial if you are unfamiliar with doing this. Name the project Notifier.
2. Create All Properties and Dummy IBActions
This is usually a good first step when tackling an application like this. Let’s get everything set up in the .h and .m files so we only have to visit Interface Builder Once. Here is what our NotifierViewController.h file looks like.
@interface NotifierViewController : UIViewController
<UITableViewDelegate,UITableViewDataSource> { IBOutlet UITableView *tableview; IBOutlet UIDatePicker *datePicker; IBOutlet UITextField *eventText; } @property (nonatomic, retain) IBOutlet UITableView *tableview; @property (nonatomic, retain) IBOutlet UIDatePicker *datePicker; @property (nonatomic, retain) IBOutlet UITextField *eventText; - (IBAction) scheduleAlarm:(id) sender; @end
Seems clear enough. We have 3 UI elements that we care about and one action. One thing to note is, your class should implement the UITableViewDelegate and UITableViewDataSource protocols. This is because we will be displaying a tableview containing all of the scheduled alarms.
Now, do all of the necessary steps in your .m file. This includes memory management for the IBOutlets and creating a dummy method for the scheduleAlarm IBAction. Your .m file should look something like this. Note: I have omitted import statements because my syntax highlighter wasn’t digging them.
@implementation NotifierViewController @synthesize datePicker,tableview, eventText; - (IBAction) scheduleAlarm:(id) sender { } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)viewDidUnload { datePicker = nil; tableview = nil; eventText = nil; } - (void)dealloc { [super dealloc]; } @end
Now it’s time to build our interface. Open Interface builder and construct an interface like this.
If you want my super sweet green button image, here it is:
After creating the interface, make sure you hook up all of the UI components to their corresponding IBOutlets and hook up the touchUpInside: method of the button the your scheduleAlarm: IBAction. For more info on hooking up IBOutlets, check out this tutorial.
3. Implement UITableViewDelegate and UITableViewDataSource Delegate methods to List Currently Scheduled Local Notifications
It may seem weird to implement the code to display the notifications before the code that creates them, however I like this approach better. This way, once we schedule the notifications, they automagically appear in our table. Add the following code to your .m file.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // We only have one section return 1; } - (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section { // Return the number of notifications return [[[UIApplication sharedApplication] scheduledLocalNotifications] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease]; } // Get list of local notifications NSArray *notificationArray = [[UIApplication sharedApplication]
scheduledLocalNotifications]; UILocalNotification *notif = [notificationArray objectAtIndex:indexPath.row]; // Display notification info [cell.textLabel setText:notif.alertBody]; [cell.detailTextLabel setText:[notif.fireDate description]]; return cell; }
OK, finally some “real” code. Most of this code should seem pretty straight forward. If not, check out this tutorial on UITableViews.
So, the new code here is dealing with retrieving a list of scheduled notifications. Calling the scheduledLocalNotifications method of UIApplication will return an NSArray of all notifications scheduled by the current app. We just index into this array and grab each notification.
Finally, we are displaying the alertBody (text that displays when the notification fires) and the fireDate (date and time when the notification will display) in the tableview cell.
4. Scheduling Notifications
And now for the moment you’ve been waiting for… OK, probably not, but definitely the most exciting (least boring) part of this tutorial. Let’s implement that scheduleAlarm: IBAction that you framed out earlier. Update your .m file to contain the following code.- (IBAction) scheduleAlarm:(id) sender { [eventText resignFirstResponder]; NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; // Get the current date NSDate *pickerDate = [self.datePicker date]; // Break the date up into components NSDateComponents *dateComponents = [calendar
components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:pickerDate]; NSDateComponents *timeComponents = [calendar
components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:pickerDate]; // Set up the fire time NSDateComponents *dateComps = [[NSDateComponents alloc] init]; [dateComps setDay:[dateComponents day]]; [dateComps setMonth:[dateComponents month]]; [dateComps setYear:[dateComponents year]]; [dateComps setHour:[timeComponents hour]]; // Notification will fire in one minute [dateComps setMinute:[timeComponents minute]]; [dateComps setSecond:[timeComponents second]]; NSDate *itemDate = [calendar dateFromComponents:dateComps]; [dateComps release]; UILocalNotification *localNotif = [[UILocalNotification alloc] init]; if (localNotif == nil) return; localNotif.fireDate = itemDate; localNotif.timeZone = [NSTimeZone defaultTimeZone]; // Notification details localNotif.alertBody = [eventText text]; // Set the action button localNotif.alertAction = @"View"; localNotif.soundName = UILocalNotificationDefaultSoundName; localNotif.applicationIconBadgeNumber = 1; // Specify custom data for the notification NSDictionary *infoDict = [NSDictionary
dictionaryWithObject:@"someValue"
forKey:@"someKey"]; localNotif.userInfo = infoDict; // Schedule the notification [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; [localNotif release]; [self.tableview reloadData]; }
Another important bit of code is where we set the alertBody or the notification. In this example we set it to the text that the user entered into the text field. You can set this to whatever you like.
The other thing I want to mention is the infoDict in the code. This dictionary is your chance to associate some additional information with the alert. For example, if you are using this alert in a game like We Rule to notify you when a crop is ready. You might want to set a key and value that contains the id of the crop that has completed. For now, we just set some arbitrary values and you can ignore them if you like.
After actually scheduling the notification, we just reload the tableview to get it to display immediately.
5. Handling Notifications After They Fire
The last piece of this puzzle is determining what to do when a notification fires. Fortunately, this step is very easy and handled inside of the appDelegate. When a notification fires, there are one of two situations. 1. The app is running and 2. The app is not running (or running in the “background”) .Open up your app delegate .m file and add the following code.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // Add the view controller's view to the window and display. [window addSubview:viewController.view]; [window makeKeyAndVisible]; application.applicationIconBadgeNumber = 0; // Handle launching from a notification UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; if (localNotif) { NSLog(@"Recieved Notification %@",localNotif); } return YES; } - (void)application:(UIApplication *)app
didReceiveLocalNotification:(UILocalNotification *)notif { // Handle the notificaton when the app is running NSLog(@"Recieved Notification %@",notif); }
Finally, we implement the didReceiveLocalNotification method. This method is required if you want to handle notifications at all in your app. You will see this method fire when the app is running and you receive a local notification. When the app is running, you will not see the UIAlertView show up with the notification data.
Notifier Source Code
No comments:
Post a Comment