views:

6034

answers:

6

My app uses NSTimer and it appears that NSTimer doesn't fire when the iPhone goes into the stand-by mode (either by pressing the hardware button or by the idle timer).

When I activate the iPhone again, my app is still in the foreground. What happens to third party apps when the iPhone is the stand-by mode?

+11  A: 

See Application Interruptions in the iPhone OS Programming Guide, especially the applicationWillResignActive and applicationDidBecomeActive events. (The whole guide is certainly worth reading.) When You ignore the events, the timer seems to go on for a while and then stops. Sounds logical, the application could easily drain the battery if kept running. And what exactly happens to the application? I guess it simply does not get any CPU time – it freezes and only thaws when You turn the machine back “on.”

zoul
Thanks for your answer. The reference to iPhone Programming Guide helped me understand what's going on.
subjective-c
I've implemented those two methods, and the timer still stops after a while. According to the Guide the application still executes but it doesn't not dispatch events. Is there are way to keep the timer going when the app is in the suspended state?
subjective-c
I would assume it puts the run loop into a special mode. If you can figure out what this mode is, then you should be able to run your timer.Note that this is a complete guess
Kevin Ballard
According to the Guide the app should not do anything when suspended. Attempting the opposite looks like a good way to have your app rejected.
zoul
@zoul the way I read the Guide it says that when in suspended mode the app should use the least amount of battery power not that it shouldn't do anything. There are other apps in the AppStore that seem to have some kind of timer active while the iPhone is locked. I just don't know how they did it.
subjective-c
A: 

I believe your application should run normally when suspended. (think Pandora Radio)

Check to see if your timer is being deallocated due to your view being hidden or some other event occurring.

Adam Douglass
Pandora takes advantage of one of a few modes of sound playback that allows for it to continue to operate even when the screen is locked.
mahboudz
+31  A: 

Although it's not evident here, I believe the original poster did find an answer to his question by starting a thread (available here) in the iPhone Developer Forums (which I eventually had to find myself because the information wasn't shared here).

In case someone else has the same question and finds the page in the future, here's a helpful response that was posted by someone on the Apple forum called "eskimo1" (which I have edited slightly such that it is easier to read without having the context provided by the entire original thread):

  • Regarding iPhone app status terminology, "active" does not mean "awake", it means "attached to the GUI". Think of it being analogous to "frontmost" in Mac OS X. When you lock the device your app deactivates but the device may or may not go to sleep
  • iPhone OS rarely sleeps if the device is connected to main power (i.e., via USB). It can sleep if running on battery, however.
  • A short time after the screen is locked (20 seconds according to Oliver Drobnik), the device sleeps. This is like closing the lid on your laptop; all activity on the main CPU halts.
  • This does not happen if the device is playing audio in the right audio session. See DTS Q&A QA1626 "Audio Session - Ensuring audio playback continues when screen is locked" for details.
  • Note that the idleTimerDisabled property (which can be turned on to prevent the screen from turning off while the app is running) is about locking the screen after user inactivity. It's not directly related to system sleep (it's indirectly related in that the system may sleep shortly after it's locked).
Clint Harris
Thanks Clint. I meant to post a link to that thread here but never got around to do it.
subjective-c
Clint, that was useful. Thanks!
Garth T Kidd
+2  A: 

My first advice is do not disable the idle timer, that is just a hack. If you want to keep a timer alive during UI events run the timer on the current run loop using NSCommonModes:

// create timer and add it to the current run loop using common modes

self.timer = [NSTimer timerWithTimeInterval:.1 target:self selector:@selector(handleTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
astar
Could you explain this in a bit more depth? How does NSCommonModes keep the timer firing even during device sleep?
Carl Coryell-Martin
A: 

I was faced with this issue recently in an app I am working on that uses several timers and plays some audio prompts and made two relatively simple changes:

One. in the AppDelegate I implemented the following methods and there mere presence allows the app to continue when the screen is locked

// this receives the notification when the device is locked
- (void)applicationWillResignActive:(UIApplication *)application
{ 
}

// this receives the notification that the application is about to become active again
- (void)applicationWillBecomeActive:(NSNotification *)aNotification
{
}

references: UIApplicationDelegate Protocol Reference & NSApplication Class Reference in the API doc accessible via Xcode, just search for applicationWillBecomeActive

Two. made the main viewcontroller class an AVAudioPlayerDelegate and used this code from Apple's "AddMusic" sample to make the audio alerts the app played mix nicely into the iPod audio etc... I just dropped this code into a method that is called during viewDidLoad now if this interests you, you fall into the "who should read this doc" category for this: Audio Session Programming Guide

// Registers this class as the delegate of the audio session. [[AVAudioSession sharedInstance] setDelegate: self];

// The AmbientSound category allows application audio to mix with Media Player // audio. The category also indicates that application audio should stop playing // if the Ring/Siilent switch is set to "silent" or the screen locks. [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];

// Activates the audio session. NSError *activationError = nil; [[AVAudioSession sharedInstance] setActive: YES error: &activationError];

Best of luck!

echobravo
A: 

I used the information on this post for a small sample that I was building. This is the code that I used when I initiated the playback to prevent the audio from stopping:

AudioSession.Category = AudioSessionCategory.MediaPlayback;

And when the application is done with the playback to reset to the original value:

AudioSession.Category = AudioSessionCategory.SoloAmbientSound;

The full sample is here:

http://github.com/migueldeicaza/monotouch-samples/tree/master/StreamingAudio/

miguel.de.icaza