I have an app that runs a timer, and the timer should keep running even if the app quits or the phone is turned off.
So I'm trying to do that using shouldSaveApplicationState
and shouldRestoreApplicationState
. I added both methods and willFinishLaunchingWithOptions
to my appDelegate and I set up restoration IDs for every view controller, navigation controller and tab bar controller involved.
Then on the view controller I want to restore I did this:
override func encodeRestorableStateWithCoder(coder: NSCoder) {
coder.encodeObject(startDate, forKey: "startDate")
coder.encodeObject(startTime, forKey: "startTime")
coder.encodeObject(elapsedTime, forKey: "elapsedTime")
coder.encodeObject(playing, forKey: "playing")
coder.encodeObject(timerLabel.text, forKey: "timerLabelText")
super.encodeRestorableStateWithCoder(coder)
}
override func decodeRestorableStateWithCoder(coder: NSCoder) {
startDate = coder.decodeObjectForKey("startDate") as! NSDate
startTime = coder.decodeObjectForKey("startTime") as! NSTimeInterval
elapsedTime = coder.decodeObjectForKey("elapsedTime") as! NSTimeInterval
playing = coder.decodeObjectForKey("playing") as! Bool
timerLabel.text = (coder.decodeObjectForKey("timerLabelText") as! String)
super.decodeRestorableStateWithCoder(coder)
}
override func applicationFinishedRestoringState() {
if playing {
elapsedTime += startDate.timeIntervalSinceNow
play()
}
}
Now here's the weird part. When my phone is connected to Xcode and I use Xcode's play and stop buttons to start and to quit the app everything works as it should. When I try the same thing with the phone disconnected from Xcode, though, it's like I didn't even set up the state restoration at all, the app ignores it completely and just shows the first view controller. And I can't even debug because when I connect the phone to Xcode it works out. The same thing happens on the simulator. If I use Xcode's buttons the restoration works. If I just open and close the app from the simulator itself, it doesn't.
Any ideas?
State restoration does not work when the user actively "kills" your app from the multitask menu. It only works when the system silently kills your app in the background to reclaim resources (e.g., memory).
The rationale (what follows is my own speculation/interpretation) would be that, the whole purpose of state restoration is for the user to come back to the app as they left it last time, as if it never was terminated (from the user's point of view).
But if the user explicitly kills the app, it means they don't expect it to be "still running, as they left it".
Source: This part of Apple's docs states that:
- The system automatically deletes an app’s preserved state when the user force quits the app. Deleting the preserved state information when the app is killed is a safety precaution. (As a safety precaution, the system also deletes preserved state if the app crashes twice during launch.) If you want to test your app’s ability to restore its state, you should not use the multitasking bar to kill the app during debugging. Instead, use Xcode to kill the app or kill the app programmatically by installing a temporary command or gesture to call exit on demand.
Killing the app from Xcode ("stop button") replicates the "non-user initiated termination", hence it respects state preservation/restoration flow.