NSTimer : applicationDidEnterBackground : countdown (how to keep state) - iphone

I have a simple countdown timer that updates a label every second. How do I keep state or the illusion of it when hitting the home button or when the app gets put in the background?

Actually, you don't need to run in the background if all you need to do is maintain a timer. In your app delegate's applicationWillTerminate:, create an NSDictionary containing the NSTimer's fire time and write it to a plist using -[NSDictionary writeToFile:atomically:], then read it back in using -[NSDictionary initWithContentsOfFile:] somewhere in your app delegate'sapplication:didFinishLaunchingWithOptions:.
If you are running in the background anyway, do the same in applicationDidEnterBackground: and applicationWillEnterForeground:. If you use this solution, be sure to invalidate the timer after you write the plist.

Related

How to start the first view every time when app resumes?

I am using xcode4.2 and inside appDidFinishLaunching i am initializing navigationController with my first view and sets the rootViewController of app to navigationController.I want to show the first view every time when app resumes. How i can i do this?
The easiest way I can think of is not using backgrounding. If you set the UIApplicationExitsOnSuspend key in Info.plist, when the user press the home button, your app will quit and next time it is launched it will start over and not resumed from where it was.
Otherwise, you can define – applicationWillEnterForeground: and – applicationDidBecomeActive: to go back to your first view whenever the app is resumed. Have a look at the UIApplicationDelegate reference and Multitasking states.

iOS: multiple NSTimer instances using the same view - do I need to use multithreading?

I'm working on a multiview app. One of the views is a table view. Each cell has a stopwatch. I'm planning to use NSTimer for the stopwatches. Do I need to implement multithreading for the timers to work properly even when the user switches the view and then comes back later?
I did my research but most of the tutorials cover one NSTimer in a single view. I want to make sure the user can do other things while the timers are running, like use the interface, navigation, etc. In another post Placing an NSTimer in a separate thread someone said you need a different runloop for the timer. Would I need one runloop for each timer in my case? Is it advisable? Any performance drawbacks?
Thanks a lot!
One run loop should be just fine. Your interface will still be responsive.
Keep in mind that timers are never guaranteed to be accurate. They are affected by how much other stuff is on the same loop. Its ok to use the timer to update the display but not to actually measure time. Set an NSDate when you start a stop watch then compare the current date with that start date each time your display timer updates the display.
Since you should only use the NSTimer to update the display, could you just use one generic display update timer that updates all running stopwatches, instead of having one for each stopwatch?

iPhone - Get user interaction event and automatic logout

In my iPhone app I want to logout the user if nothing happens till about 2 minutes (e.g. the user puts down the phone). Does anybody has such issue? What is the best way to implement this feature? I think I save the date of last event to NSUserDefaults, then on the next event first I check the current date. If the difference is larger than 2 minutes go to login screen, else refresh the stored date. But how can I get the touch event generally?
Thanks, madik
There's a method in UIApplicationDelegate for that:
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
Note that it also will be called when the app is going to background state. That will help you store the data whenever the app is going to inactive state. If you want to check if a certain amount of time has passed, you will have to use a NSTimer and store the last touch event. I think it cannot be done because you can't intercept all the touch events (Maybe it's over an object managed by the system. The status bar is an example). I guess is better to let the system to manage all the activity/inactivity stuff and store your data when necessary.
EDIT: I didn't understand what you mean the first time. Check this accepted answer, it accomplish what you need. Basically you have to subclass UIApplication and override sendEvent method.
'NSTimer'
When you say "how can I get the touch event generally?", if you mean how can you tell if the user is idle or not, you'll have to set up some system to gather all touch events at a higher level in your app. You could update the last touch time you mentioned in NSUserDefaults but that may be inefficient during the run of the app, so you could just post the touch event to your main app delegate and have it save the time of last touch. Which would also be where you could set up the 2 minute timer.
Something like:
- (void) someAppDelegateMethodThatYouCallForAnyUserEvent
{
[self.idleTimer invalidate];
self.lastEvent = [NSDate now];
self.idleTimer = [NSTimer scheduledTimerWithTimeInterval:120 target:self selector:#selector(logoutAndGotoLogin) userInfo:nil repeats:NO];
...
}
You'll also have to do some cleanup in your app delegate methods when the app goes to background etc if you support that behavior.

Saving NSTimer to NSUserDefaults

I'm doing a simple game for the iPhone and now that is finished, I'd like to add a timer. I managed to implement the timer, but now I want to pause it when an incoming SMS or Phone Call minimize the application.
I thought that I should put the timer in the app delegate and, when applicationWillResignActive/applicationDidBecomeActive will be called, save/restore the timer object with NSUserDefaults, but I see that I can only save "raw" data, not entire objects.
How can i manage this trouble?
You'll need to store the elapsed time in a variable (I wouldn't use NSUserDefaults) and then create a new timer with the elapsed time subtracted.
See this question for some more info: How can I programmatically pause an NSTimer?

iPhone 4: when to save data?

I have an app (a game) which saves data: game state, high scores, achievements, etc. Currently the app delegate does this on applicationWillTerminate:. After playing around with iPhone 4 for a bit, it seems that applications pretty much never terminate: they just run in the background forever, unless the user goes out of their way to quit them, or restart the phone.
So my question is, should I find another place to save my data, and if so, when?
To minimize the amount of time spent in the delegate method call, you should find a place that makes sense to save during the game (level completion, checkpoints, etc). You can also add a new delegate method to your application delegate which will be called when your application transitions to the background where you can duplicate some of the things you may have done previously in applicationWillTerminate:. The new delegate method to implement is -applicationDidEnterBackground:.
You will also receive a notification that the user switched back to your app as applicationWillEnterForeground:.
you can do so in the views diddisappear delegate method
-(void)viewDidDisappear:(BOOL)animated
{
//CODE FOR SAVING
}
There are 2 App delegate methods you can use
applicationDidResignActive: //pausing the app, used when a msg comes up. if multitasking this wont help
applicationDidEnterBackground: // called in iOS 4 for when the app is in the background
you can see when it loads into the foreground using
applicationWillEnterForeground:
check out the reference for more info
You should save in applicationDidEnterBackground. Make sure to wrap your saving code with – beginBackgroundTaskWithExpirationHandler: and endBackgroundTask, since without that, you have less than a second (or something like that) before execution suspends.