UIApplication -scheduleLocalNotification: very slow when called by UIApplication -appWillTerminate: - iphone

I set the "application does not run in background" in my info.plist, so when user tap home button, app quits.
When my [UIApplication -appWillTerminate:] called, I will schedule 64 local notifications to system, all of them are non-repeating.
but that take a seemingly long time(6.17 seconds) on a iPhone4 with iOS6.0.1.
When I look at the time profiler, I found that the curve is very strange, it don't take much CPU time, but it do take a lot of time.
Also when I look at the call tree, 93% of the time is spent on [UIApplication -scheduleLocalNotification:] in the time range showed in the image.
Why?
This is how I generate my notifications:
UILocalNotification *n = [[[UILocalNotification] alloc] init] autorelease];
n.alertBody = #"some body";
n.hasAction = YES;
n.alertAction = #"some action";
n.fireDate = #"some date";
n.repeatInterval = 0;
n.soundName = #"my sound"
n.userInfo = aDictionaryWithAStringAbount10CharacterLongAnd2NSNumber.
[self.notifications addObject:n];
This is how I schedule my notifications:
-(void)endProxyAndWriteToSystemLocalNotification
{
_proxying = NO;
NSDate *dateAnchor = [NSDate date];
NSEnumerator *enumerator = [self.notifications objectEnumerator];
NSInteger i = 0;
while (i < maxLocalNotifCount) {
UILocalNotification *n = [enumerator nextObject];
if (!d) {
break;
}
if ([n.fireDate timeIntervalSinceDate:dateAnchor] >= 0) {
[[UIApplication sharedApplication] scheduleLocalNotification:n];
i++;
}
}
[self.notificationDatas removeAllObjects];
}

This would help:
-(void)endProxyAndWriteToSystemLocalNotification {
[[UIApplication sharedApplication] setScheduledLocalNotifications:self.notifications];
}
iOS 4.2 and later
read UIApplication Class Reference for detailed description

I think the problem is that you are trying to schedule 64 local notifications. Is there a reason to do all of these on app termination? Apples scheduleLocalNotification was not designed to be called so many times on termination

Related

How to deliver five notification for five different times everyday?

I am working on an islamic PrayerTimes app that gives five prayertimes a day.So my goal for now is to deliver five notifications to the user everyday at specific prayerTimes. then i created five notifications for each prayers , assigned five firedate for each notification, and i can get the notification delivered .
However , my problem is every time i run the app or restart the app i am having a notification on notification center, at the console area i can see all the older notifications are delivered as well (I overrode application:didReceiveLocalNotification: method).
Frankly I am not a experienced developer , i really didn't get this , and I thought my code is very long.
So can somebody help me and tell how can i manage to do this ? :) (my english is not that good please be tolerant). if i missed some other sing to inform ,please tell.
Here is my code ;
Edit: I call this mehod from viewDidLoad.
I got five times in an array blow:
NSSArray *timeArray = #[time0,time1,time2,time3,time4];
I sceduled five UILocalNotification like this:
if (localNotification0 != nil) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification0];
}
NSDate *date0 = [_timeArray objectAtIndex:0];
NSLog(#"date %#",date0);
localNotification0 = [[UILocalNotification alloc] init];
localNotification0.fireDate = date0;
localNotification0.timeZone =[NSTimeZone defaultTimeZone];
NSLog(#"firedate %#",localNotification0.timeZone);
localNotification0.alertBody = #"Se";
localNotification0.soundName = _adhanName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification0];
if (localNotification1 != nil) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification1];
}
NSDate *date1 = [_timeArray objectAtIndex:1];
localNotification1 = [[UILocalNotification alloc] init];
localNotification1.fireDate = date1;
NSLog(#"firedate %#",localNotification1.fireDate);
localNotification1.timeZone =[NSTimeZone defaultTimeZone];
localNotification1.alertBody = #"Se";
localNotification1.soundName = _adhanName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification1];
[localNotification1 release];
if (localNotification2 != nil) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification2];
}
NSDate *date2 = [_timeArray objectAtIndex:2];
localNotification2 = [[UILocalNotification alloc] init];
localNotification2.fireDate = date2;
localNotification2.timeZone =[NSTimeZone defaultTimeZone];
NSLog(#"firedate %#",localNotification2.fireDate);
localNotification2.alertBody = #"Se";
localNotification2.soundName = _adhanName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification2];
[localNotification2 release];
if (localNotification3 != nil) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification3];
}
NSDate *date3 = [_timeArray objectAtIndex:3];
localNotification3 = [[UILocalNotification alloc] init];
localNotification3.fireDate = date3;
localNotification3.timeZone =[NSTimeZone defaultTimeZone];
NSLog(#"firedate %#",localNotification3.fireDate);
localNotification3.alertBody = #"Se";
localNotification3.soundName = _adhanName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification3];
[localNotification3 release];
if (localNotification4 != nil) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification4];
}
NSDate *date4 = [_timeArray objectAtIndex:4];
localNotification4 = [[UILocalNotification alloc] init];
localNotification4.fireDate = date4;
localNotification4.timeZone =[NSTimeZone defaultTimeZone];
NSLog(#"firedate %#",localNotification4.fireDate);
localNotification4.alertBody = #"Se";
localNotification4.soundName = _adhanName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification4];
[localNotification4 release];
Is there other more easy way to do this ? pleas help me out!
For starters, it looks like you can shorten your code by using a loop, something like this:
for (NSDate *time in times) {
if (localNotification3 != nil) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification3];
}
UILocalNotification *note = [[UILocalNotification alloc] init];
note.fireDate = time;
note.timeZone =[NSTimeZone defaultTimeZone];
note.alertBody = #"Se";
note.soundName = _adhanName;
[[UIApplication sharedApplication] scheduleLocalNotification:note];
[note release]; // no need to release note if you use ARC
}
That loop will run once for each entry in your times array, reducing the amount of code you need by a factor of 5, in this case, or [times count] in general.
every time i run the app or restart the app i am having a notification on notification center
I'm not sure I fully understand what's wrong here, but if any/all the notifications are being presented too soon, it sounds like you should check the times for which they're scheduled. If the problem is that your app keeps scheduling new notifications every time it starts, resulting in too many notifications, then you have at least two options:
use -cancelAllLocalNotifications before you schedule any new notifications
record the times for which notifications have already been scheduled (NSUserDefaults is good for that kind of thing) and avoid scheduling new notifications for those times

How to initialize local notification?

I want to implement local notification in my clock app.Basically i want that a music file should be played after every half an hour like in ship's clock in which chimes are played after every 30 minutes.
Can anyone give rough idea as how i can implement this functionality even when the app enters in background?
I recently used the Local notification stuff and used the following functions
//Setting up the Local Notifications
for (int i= 1 ; i<=10; i++) { //We here set 10 Notification after every 30 minutes from now you can modify it accordingly
NSDate *scheduled = [[NSDate date] dateByAddingTimeInterval:60*30*i]; //These are seconds
NSDictionary* dataDict = [NSDictionary dictionaryWithObjectsAndKeys:scheduled,FIRE_TIME_KEY,#"Background Notification received",NOTIFICATION_MESSAGE_KEY,nil];
[self scheduleNotificationWithItem:dataDict];
}
Where scheduleNotificationWithItem is defined as
- (void)scheduleNotificationWithItem:(NSDictionary*)item {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
if (localNotification == nil) return;
localNotification.fireDate = [item valueForKey:FIRE_TIME_KEY];
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.alertBody = [NSString stringWithFormat:NSLocalizedString(#"%#", nil), [item valueForKey:NOTIFICATION_MESSAGE_KEY]];
localNotification.alertAction = NSLocalizedString(#"View Details", nil);
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.userInfo = item;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[localNotification release];
}
Finally you can handle these notifications as
You can handle these notifications as follows
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
// Do the required work you can obtain additional Info via notification.userInfo which happens to be a dictionary
}
reading the developer documentation will help you more to understand the stuff.Hope it helps
You can use UILocalNotifications and set their 'firedate', according to your requirement and then schedule the notification. These notifications doesn't bother whether your app is running or is in background they will always show up like an alertview.

Setting Local Notifications on a new thread?

I need to know if it is possible to create a new thread to handle setting local notifications.
My app depends heavily on these notifications, so I want to make the app work while the phone sets the notifications.
Example:
(now)
you launch the app, the app hangs at the splash screen to set the local notifications, then it launches.
(I want)
The app launches and is usable while the Local notifications are set.
I need some sample code, too, please :)
(for the record, i am setting 60 local notifications each time the app enters foreground for my own reasons...)
Thanks!!
Yes this can be done, I do it all the time:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Add the navigation controller's view to the window and display.
[NSThread detachNewThreadSelector:#selector(scheduleLocalNotifications) toTarget:self withObject:nil];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
-(void) scheduleLocalNotifications
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (int i = 0; i < 60; i++)
{
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
NSDate *sleepDate = [[NSDate date] dateByAddingTimeInterval:i * 60];
NSLog(#"Sleepdate is: %#", sleepDate);
localNotif.fireDate = sleepDate;
NSLog(#"fireDate is %#",localNotif.fireDate);
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(#"This is local notification %i"), i];
localNotif.alertAction = NSLocalizedString(#"View Details", nil);
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
NSLog(#"scheduledLocalNotifications are %#", [[UIApplication sharedApplication] scheduledLocalNotifications]);
[localNotif release];
}
[pool release];
}
Taken from a project I am working on now, I can confirm that It works as expected.
EDIT:
Example was leaking in scheduleLocalNotifications because handling the NSAutoreleasePool was missing – now it's added to the example.
One way to do threads is with is with performSelectorInBackground.
For example:
[myObj performSelectorInBackground:#selector(doSomething) withObject:nil];
You should note, however, that Apple is pretty strongly recommending that you use higher-level concepts like NSOperations and Dispatch Queues instead of explicitly spawning threads. See the Concurrency Programming Guide

UILocalNotification repeat sound

I have used the code from apples example from this page: Link, but I can't seem to get the sound to repeat. I have checked other applications, such as skype (for VOIP) and Alarm Clock Pro (audio?) but I cannot get the sound file to be repeated.
This is my code:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
AlarmHandler *AHinstance = getAlarmHandlerInstance();
UIApplication* app = [UIApplication sharedApplication];
NSArray *alarmList = [AHinstance getAlarms];
NSArray *oldNotifications = [app scheduledLocalNotifications];
if ([oldNotifications count] > 0)
{
[app cancelAllLocalNotifications];
}
for (Alarm *theAlarm in alarmList) {
NSDate *alarmDate = [theAlarm getNearestActivationDate];
Package *alarmPackage = [theAlarm getAlarmPackage];
NSArray *fileList = [alarmPackage getVoiceFileListForBackgroundNotificationWithHour:theAlarm.larmHour];
if( alarmDate == nil ) continue;
UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
if (alarm)
{
NSLog(#"File: %#", [fileList objectAtIndex:0]);
alarm.fireDate = alarmDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.soundName = [fileList objectAtIndex:0];
alarm.alertBody = #"Time to wake up!";
alarm.repeatInterval = 0;
[app scheduleLocalNotification:alarm];
}
}
}
Any suggestions on how I can fix this?
I have had suggestions to register app as audio player and play sounds in the background, but it seems that apple does take kindly to those applications because they aren't real audio players. Therefore they deny those apps.
Regards,
Paul Peelen
There is no way to do this for local notifications. You can either register as a VOIP app or as a "background audio" app, which have separate APIs. However, if you do not provide appropriate functionality to qualify for those kinds of uses, you'll most likely be rejected.
Yes this is possible, as the documentation states:
Your own applications can schedule up to 128 simultaneous notifications, any of which can be configured to repeat at a specified interval
You just need to configure the repeatInterval property:
The calendar interval at which to reschedule the notification.

iPhone app crashing on local notification

This is weird. My application schedules local notifications whenever it is sent into the background, and while the first notification is being displayed correctly, as soon as the one after that should be fired, the whole application crashes. Yes, in the background. While no code is being executed.
No console output is given, I just get a dialog box that says "The simulated application quit" in iPhone simulator. On an actual iPhone I get dumped back to the springboard.
Here's the relevant code for the notifications. Thanks for your help.
- (void)scheduleLocalNotificationsForAlarmsWithNextAlarmAt:(NSDate *)theFireDate ofType:(int)workPlayType {
BOOL backgroundSupported = NO;
UIDevice* device = [UIDevice currentDevice];
if ([device respondsToSelector:#selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;
if(!backgroundSupported) return;
int work_minutes = [[NSUserDefaults standardUserDefaults] integerForKey:#"work_minutes_preference"];
int play_minutes = [[NSUserDefaults standardUserDefaults] integerForKey:#"play_minutes_preference"];
int workPlayStatusForNotif = workPlayType;
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
if (workPlayStatusForNotif == 1) {
localNotif.alertBody = #"Work";
localNotif.repeatInterval = work_minutes;
} else {
localNotif.alertBody = #"Play";
localNotif.repeatInterval = play_minutes;
}
localNotif.fireDate = theFireDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertAction = NSLocalizedString(#"View Details", nil);
localNotif.soundName = #"ding.caf";
localNotif.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];
// now the other one
localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
if (workPlayStatusForNotif == 0) {
localNotif.alertBody = #"Work";
localNotif.fireDate = [theFireDate dateByAddingTimeInterval:(float)work_minutes*60];
localNotif.repeatInterval = work_minutes;
} else {
localNotif.alertBody = #"Play";
localNotif.fireDate = [theFireDate dateByAddingTimeInterval:(float)play_minutes*60];
localNotif.repeatInterval = play_minutes;
}
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertAction = NSLocalizedString(#"View Details", nil);
localNotif.soundName = #"ding.caf";
localNotif.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];
}
It seems to be an iOS 4.1 bug. I have similar problems with my app which used to work with 4.0. Also other people reported problems like that in the apple developer forums. Waiting for an response from apple.
Greetings,
Ben
on which device you are testing on? where do you check if the device is iPhone3G? This code is not going to run on Iphone3g even it is on iOS4 as iPhone3G is not supported multitasking.
Rest of the code looks OK.
Yes It is an iOS 4.1 issue, I've also faced same kind of issue "Simulator crashed" but I've also experienced another issue that is:
If we fire more-than one Local-Notification in the background, then it also crashed iPhone iOS :S
I'm unable to find any workaround to execute more-than one Local Notification. Apple Development team must have to validate Local-Notification deeply.