How would I make my timer run in the background and then send a local notification? - iphone

For some reason my timer only runs in the foreground. I've searched here for solutions but I couldn't find any good ones. My timer uses Core Data and my timeInterval is saved after every decrement. Also, I'm sending a UILocalNotification but that doesn't work. I'm assuming it doesn't send a alert view if its in the foreground..Well this is what I have now:
-(IBAction)startTimer:(id)sender{
if (timer == nil) {
[startButton setTitle:#"Pause" forState:UIControlStateNormal];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
} else {
[startButton setTitle:#"Resume" forState:UIControlStateNormal];
[timer invalidate];
timer = nil;
}
}
-(void)timerAction:(NSTimer *)t
{
if(testTask.timeInterval == 0)
{
if (self.timer)
{
[self timerExpired];
[self.timer invalidate];
self.timer = nil;
}
}
else
{
testTask.timeInterval--;
NSError *error;
if (![self.context save:&error]) {
NSLog(#"couldn't save: %#", [error localizedDescription]);
}
}
NSUInteger seconds = (NSUInteger)round(testTask.timeInterval);
NSString *string = [NSString stringWithFormat:#"%02u:%02u:%02u",
seconds / 3600, (seconds / 60) % 60, seconds % 60];
timerLabel.text = string;
NSLog(#"%f", testTask.timeInterval);
}
-(void)timerExpired{
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"Time is up";
localNotification.alertAction = #"Ok";
localNotification.timeZone = [NSTimeZone defaultTimeZone];
[[UIApplication sharedApplication]presentLocalNotificationNow:localNotification];
}
I would really appreciate some guidance to making my timer work in the background (just like Apple's timer). I'm not sure how I would use NSDateComponents since I also need the testTask.timeInterval to be updated even when the application in the background..

UIBackgroundTaskIdentifier bgTask =0;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerCountDown:)
userInfo:nil
repeats:YES];
Now use this method to fire your notification. The timer will run in background.

As Josh Caswell wrote, you should save your timer state before your app goes in the background and then retrieve it when your app comes in the foreground again.
If you need to send a local notification at the right moment you can set it this way before entering the background, using your timer's state:
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyyMMddHHmmss"];
NSDate *when = [dateFormat dateFromString:desiredTime];
// desiredTime -> time you want your local notification to be fired, take this from your timer before app enters the background
[dateFormat release];
localNotification.fireDate = when;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = #"Hey";
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[localNotification release];
EDIT: In your appDelegate you should find these methods:
(1) - (void)applicationWillResignActive:(UIApplication *)application
(2) - (void)applicationDidEnterBackground:(UIApplication *)application
(3) - (void)applicationWillEnterForeground:(UIApplication *)application
(4) - (void)applicationDidBecomeActive:(UIApplication *)application
(5) - (void)applicationWillTerminate:(UIApplication *)application
These are implemented specifically to manage the behavior of your app when its state changes.
There you can do everything needed before entering the background and when resumed.
Before entering the background you have some seconds to perform local notification schedule and save your timer state (using for example NSUserDefaults).
After that Apple will probably kill your app, if it doesn't try to work in the background for one of these reasons:
Implementing Long-Running Background Tasks For tasks that require more
execution time to implement,you must request specific permissions to
run them in the background without their being suspended. In iOS, only
specific app types are allowed to run in the background:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Newsstand apps that need to download and process new content
Apps that receive regular updates from external accessories
Taken from here.
I suggest you read this, about background tasks.

Related

iOS Alarm Clock

I have created a simple alarm notification App through which I can get real time, set alarm on or off, and play a single tone audio. But I need to play a sound which should start with a class VOID.
Below is the code:
To get and start alarm notification:
- (void)viewDidLoad {
[super viewDidLoad];
dateTimerPicker.date = [NSDate date];
}
- (void)presentMessage:(NSString *)message {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Hello!"
message:message
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
}
- (void)scheduleLocalNotificationWithDate:(NSDate *)fireDate {
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.fireDate = fireDate;
notification.alertBody = #"Time to wake up!!";
notification.soundName = #"PhoneOld.mp3";
[self playPause];
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
- (IBAction)alarmSetOn:(id)sender{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeZone = [NSTimeZone defaultTimeZone];
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.dateStyle = NSDateFormatterShortStyle;
NSString *dateTimeString = [dateFormatter stringFromDate:dateTimerPicker.date];
NSLog(#"Alarm Set: %#", dateTimeString);
[self scheduleLocalNotificationWithDate:dateTimerPicker.date];
[self presentMessage:#"Alarm ON!"];
}
- (IBAction)alarmSetOff:(id)sender {
NSLog(#"Alarm Off");
[[UIApplication sharedApplication] cancelAllLocalNotifications];
[self presentMessage:#"Alarm OFF!"];
}
This is my VOID:
- (void)playPause {
RADAppDelegate *appDelegate = (RADAppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.radiosound == 0){
[appDelegate.radiosound play];
} else {
[appDelegate.radiosound pause];
}
}
How can I set the alarm to start playing the radiosound if is rated 0, like a:
notification.soundName = [self playPause];
But I know this is a NSString.
You don't need to assign a sound name to scheduled notification, just invoke the playPause method and get the name of sound file from notification, as shown below and just assign it to NSString and set property to it in appDelegate and access it to play that file.
AppDelegate.h
#property (nonatomic,strong) NSString *nsStr_soundFile;
AppDelegate.m
#synthesize nsStr_soundFile;
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification {
//Give call to play sound method.
self.nsStr_soundFile=notification.soundName;
VOID *obj=[VOID alloc]init];
[obj playPause];
}
You can make a trick with opting out of iOS multitasking by setting in your app .plist file this key UIApplicationExitsOnSuspend to YES as written here
When an app opts out, it cycles between the not-running, inactive, and
active states and never enters the background or suspended states.
An app that runs in the pre-multitasking compatibility mode keeps
running when the user locks the device while the app is in the
foreground. All the app has to do is wait for the alarm time and
execute its custom code.

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.

How can I use local notifications to wake my app?

i want that my app will run in the background and do check on somethings.
and if so the local notification will show.
i use this code in the method that check:
UIApplication *app = [UIApplication sharedApplication];
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSArray *oldNotifications = [app scheduledLocalNotifications];
if ([oldNotifications count] > 0) {
[app cancelAllLocalNotifications];
}
if (notification == nil)
return;
NSDate *notificationDate = [NSDate dateWithTimeIntervalSinceNow:10];
notification.fireDate = notificationDate;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.alertBody = #"Test Body";
[app scheduleLocalNotification:notification];
[notification release];
the problem is that when the app is in the foreground it show the alert, but if the app is in the background the notification not show to the screen.
the check that i do is running on uiwebview and reload every 10 seconds, so he need to run in the background too.
Your app won't run in background, except certain cases. Look in to this How to run the application in the background? post.

How do I present an alarm to a user, even when my application is inactive?

I want to make an app which will let you set an alarm inside my iPhone app, then have it be activated even though my app is not running.
How would I implement this?
You want to use UILocalNotification. A couple things to note before you dive in:
It's only available on iOS4 and up.
NSDate is a pain in the ass, and it's the only option for scheduling
With that said, you can begin:
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.alertBody = #"This is a Local Notification";
NSDate *date = [NSDate date];
notif.fireDate = [date addTimeInterval:600];// fire the notification in ten minutes
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
[notif release];
If you need any more help, just comment :)
try this:
in .h
int *currentTime;
in .m
-(void)startTimer {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateCurrentTime) userInfo:nil repeats:YES];
}
-(void)updateCurrentTime {
currentTime ++;
if (currentTime == userDefinedTime) {
// Time is up
}
}

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