How to handle existing data when force-closing app on iPhone? - iphone

I have loaded some values into local documents in my application. When the application is running app writes, say, 50 records.
Now, when the user force-closes the app and starts it again: The files only write the new records 50+existing 50.
How to handle this issue?

If your application is force-quit completely, you do not have an opportunity to write out additional data. No more of your code is run.
If you are talking about the force quit that happens when your app is in the background and the OS wants to free up memory, you must implement a callback in your application delegate (you can use notifications too but let's keep it simple) and observe when the OS places your app in the background. At that point, write your data to disk:
#implementaton MyAppDelegate
- (void)applicationDidEnterBackground: (UIApplication *)application {
[myDatabase commit];
[myFiles save];
[myWhatever doWhatever];
// etc.
}
#end

Related

CLLocationManager sometimes stops updating while app is in background

I have an app which uses CLLocationManager to track the user's route, drawing dots along the path taken. The app runs in the background using Required background modes > App registers for location updates.
As I understand, anything that happens in the background needs to be called from locationManager:didUpdateToLocation:fromLocation as this is the method that gets called with each location update.
The problem I'm having is that sometimes this stops getting called. It seems to happen when the user's location does not change much within the space of maybe 15 minutes or so. As far as I can tell, calls to locationManager:didUpdateToLocation:fromLocation just stop, presumably to save the battery. Unfortunately, it doesn't resume again when you're back on the move.
I presume there's no way to override this behaviour, so I would like to use Notification Centre to inform the user that the app is no longer recording the route. The problem is, how can the app know that this has happened? If locationManager:didUpdateToLocation:fromLocation is not called, I can't fire my notification. If it is being called, the notification should not fire.
Is there some kind of system notification that says location updates will cease?
I'm finding it quite hard to debug this as I can't take my Mac everywhere when I'm out and about testing the location on the device (there's only so much you can do in the simulator). Any tips for debugging would also be much appreciated!
If you haven't found the answer, I think it is because of a new attribute added to CLLocationManager called pausesLocationUpdatesAutomatically. The attribute defaults to YES, and its behaviour is exactly as you describe. Try setting it to NO and I think it will fix your problem.
Starting in iOS9, make sure you're also setting this property on your location manager:
[locationManager setAllowsBackgroundLocationUpdates:YES]
There's a delegate for location update did Fail
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
There are a few kinds of errors: kCLErrorDenied kCLErrorNetwork Add code here to handle them in the delegate method above not updating location, perhaps a UIAlertView to tell the user.
Personally, I call [locationManager stopUpdatingLocation]; on any error then restart it with an error message depending on the reason for the failure.
ALSO re background, check code in your appDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
[self saveContext];
if ([CLLocationManager significantLocationChangeMonitoringAvailable]) {
// Stop normal location updates and start significant location change updates for battery efficiency.
[self.locationHandler.locationManager stopUpdatingLocation];
[self.locationHandler.locationManager startMonitoringSignificantLocationChanges];
}
else {
NSLog(#"Significant location change monitoring is not available.");
}
}
LASTLY re: testing. You can simulate some errors in location by changing the location movement in the simulator. For example, going from running to driving will cause an error. Going from running to a single specific custom location will cause an error. They should all appear in the delegate method for locationManager above.
I've managed to solve the problem by adding a local notification that fires with a 90 second delay every time a new location is added to the route. When the next location is added, the previous notification is cancelled and a new one is scheduled. This way, if it stops updating, a notification is received by the user (albeit with a 90 second delay). It's not ideal, and it may not be great for battery life, but it is a solution and it's the best I've got for the time being.
#Ron, I meet the same problem as beev describe, and i had already set pausesLocationUpdatesAutomatically to NO. I think because iOS will kill some apps that didn't be triggered in 10 minutes when it's under background. So add local notification maybe a good choice at the moment.

Keeping an app alive in background unlimited (for a Cydia app)

I don't mind using private API's or anything of the kind that Apple doesn't like, but would prefer a quick solution that doesn't stuff like playing silence in the background or swizzling.
Obviously this isn't for the app store so please no lecturing :)
So how do you run in the background without any restrictions like "backgrounder"? I didn't manage to find an answer besides some that point people to different directions, but maybe since then someone managed to dig it up already.
Update:
This solution no longer appears to be sufficient (~ iOS 7+ or 7.1+). I'm leaving the original answer for historical reference, and in case it helps produce a future solution based on this obsolete one:
It depends on what you mean by app. If you're talking about a non-graphical background service, then what you want is a Launch Daemon. See here for how to create a launch daemon.
If you have a normal UI application, but when the user presses the home button, you want it to stay awake in the background for an unlimited time, then you can use some undocumented Background Modes in your app's Info.plist file:
<key>UIBackgroundModes</key>
<array>
<string>continuous</string>
<string>unboundedTaskCompletion</string>
</array>
Then, when iOS is ready to put your app into the background (e.g. user presses home button), you can do this, in your app delegate:
#property (nonatomic, assign) UIBackgroundTaskIdentifier bgTask;
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Delay execution of my block for 15 minutes.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 15 * 60 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
NSLog(#"I'm still alive!");
});
self.bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// should never get here under normal circumstances
[application endBackgroundTask: self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
NSLog(#"I'm going away now ....");
}];
}
Normally, iOS only gives you up to 10 minutes for your UI application to work in the background. With the undocumented background mode, you'll be able to keep alive past that 10 minute limit.
Note: this does not require hooking with MobileSubstrate. If you're using the second method (undocumented Background Modes), then it does require installing your app in /Applications/, not in the normal sandbox area (/var/mobile/Applications/).
Depending on what your "app" is going to do, you can hook MobileSubstrate. This will load with SpringBoard and essentially run "in the background".
If you want to write an actual application, then you can also write a "Dynamic Library" which will be loaded with SpringBoard by MobileSUbstrate. You can talk back and forth between this dylib and your app by using NSNotificationCenter; creating and posting notifications.

How can I call Method while app is in background in iOS?

I have one class name as myClassCalculate have the following method
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
NSLog(#"Accelerometer is called");
}
I am making object in
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
myObject = [[myClassCalculate alloc] init];
now when app will go in background, I want this
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
What can I do, so that this method will get called in app background
Thanks
You can't, only VOIP, audio and navigation apps are allowed to run in background.
Thus if your app does not fall in one of these it gets suspended and wil not receive any events.
More about backgrounding: App States and Multitasking
Declaring Your App’s Supported Background Tasks
Support for some types of background execution must be declared in
advance by the app that uses them. An app declares support for a
service using its Info.plist file. Add the UIBackgroundModes key to
your Info.plist file and set its value to an array containing one or
more of the following strings:
audio — The app plays audible content to the user while in the background. (This content includes streaming audio or video content using AirPlay.)
location — The app keeps users informed of their location, even while it is running in the background.
voip — The app provides the ability for the user to make phone calls using an Internet connection.
newsstand-content — The app is a Newsstand app that downloads and processes magazine or newspaper content in the background.
external-accessory — The app works with a hardware accessory that needs to deliver updates on a regular schedule.
At WWDC this year they said that accelerometer updates could be observed in the background but I'm not sure how to do it. I think it would be iOS 5 only.
To do background tasks you need to add them to your info.plist in the UIBackgroundModes key.
Here is what's available right now.
audio
The application plays audible content in the background.
location
The application provides location-based information to the user and requires the use of the standard location services (as opposed to the significant change location service) to implement this feature.
voip
The application provides Voice-over-IP services. Applications with this key are automatically launched after system boot so that the application can reestablish VoIP services. Applications with this key are also allowed to play background audio.
newsstand-content
The application processes content that was recently downloaded in the background using the Newsstand Kit framework, so that the content is ready when the user wants it.
This value is supported in iOS 5.0 and later.
external-accessory
The application communicates with an accessory that delivers data at regular intervals.
Try putting location in the plist or using [UIApplication beginBackgroundTaskWithHandler:]
This value is supported in iOS 5.0 and later.
When app goes in backgroound this method is called onUserLeaveHint()

Distinguish between an iPhone App crashing and being killed

Hello I am planning to develop a simple iPhone game. I would like to be able to distinguish between a genuine crash, and the user killing the app ( by double tapping home screen and long-clicking it to kill it) .
Can someone please shed some light on what exactly happens when the user kill the app through the multitasking bar.
If your app is in the background and suspended when the user kills it, it will receive no notification. This accounts for the majority of cases.
If your app is currently running in the background (there are only very specific categories of apps that can do that), then it receives applicationWillTerminate.
Indeed, Apple is very clear as to the fact that you should save any relevant data before entering the background. Have a look at this (chapter "Responding to Application Termination"):
Even if you develop your application using iOS SDK 4 and later, you must still be prepared for your application to be killed without any notification. The user can kill applications explicitly using the multitasking UI. In addition, if memory becomes constrained, the system might remove applications from memory to make more room. If your application is currently suspended, the system kills your application and removes it from memory without any notice. However, if your application is currently running in the background state (in other words, not suspended), the system calls the applicationWillTerminate: method of your application delegate. Your application cannot request additional background execution time from this method.
EDIT:
about the "saying sorry" thing...
you can certainly do that on the next launch. simply store a key in NSUserDefaults and remove it when the app enters the background (I hope all this sounds familiar to you, otherwise look into the UIApplicationDelegate protocol).
when the app starts up, you check the key; if it is there, then the app was not closed by the user; if the app is not there, then the user at least moved the app to the background and did not experience any sudden termination...
For iOS6 and later there is a way to do this. A side effect of State Restoration is that it will delete the state when there is either a crash during restore or a user manually kills the app. You can use this to your advantage to detect a user manually killing the app.
From the documentation:
Be aware 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. (The system also deletes preserved state if the app crashes at launch time as a similar safety precaution.) 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.
The following code assumes that you already have a BOOL for crash detection called _didCrashInLastSession. There are different approaches for getting this value such as this 3rd party library. In your code call the method [self getLaunchType] to see which type of launch you are dealing with and act on that accordingly. Put the following in your AppDelegate.m:
typedef NS_ENUM(NSInteger, LaunchType) {
LaunchTypeUnknown,
LaunchTypeNewInstall,
LaunchTypeNormalLaunch,
LaunchTypeCrashedLastSession,
LaunchTypeUserManualQuit,
};
static BOOL hadStateToRestore = NO;
static NSString * const kAppHasEverRunKey = #"appHasEverRun";
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
// Called when going into the background
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAppHasEverRunKey];
[[NSUserDefaults standardUserDefaults] synchronize];
return YES;
}
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
// Called on start up
hadStateToRestore = YES;
return YES;
}
- (LaunchType)getLaunchType
{
if (_didCrashInLastSession) {
return LaunchTypeCrashedLastSession;
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:kAppHasEverRunKey]) {
return LaunchTypeNewInstall;
}
if (!hadStateToRestore) {
return LaunchTypeUserManualQuit;
}
return LaunchTypeNormalLaunch;
}
Update: At least one 3rd party SDK breaks this technique: Urban Airship.
You can do it through your device also.
Connect your device to your machine.
Run xcode and go to organizer.
There select your device and device logs.
There you can also see crash logs of your app or game.

Save current state while fast context switching - iOS4

While going through the iOS-4 Multitasking for fast context switching, I have a doubt regarding save last state of application.
Do applications have to manually save the last state in "- (void)applicationDidEnterBackground:(UIApplication *)application"? Or iOS-4 will take care of it?
In the video it's mentioned as follows:
-(void)applicationDidEnterBackground:(UIApplication *)application {
// save app state
[self saveState];
// reduce memory usages
....
// prepare UI
....
// close listening sockets
....
}
Thanks in advance,
Sunil
Once your application has entered background, there's no guarantee it will ever come back to the foreground. It may at any point in time be terminated, without notification of any kind. Thus, entering background, you want to save the state or risk losing it.
To quote Apple (source: http://developer.apple.com/iphone/library/documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html),
Save your application state before moving to the background. During low-memory conditions, background applications are purged from memory to free up space. Suspended applications are purged first, and no notice is given to the application before it is purged. As a result, before moving to the background, an application should always save enough state information to reconstitute itself later if necessary. Restoring your application to its previous state also provides consistency for the user, who will see a snapshot of your application’s main window briefly when it is relaunched.
Do applications have to manually save the last state in "- (void)applicationDidEnterBackground:(UIApplication *)application"? Or iOS-4 will take care of it?
Yes, if you want your app to restore after it's been killed, you need to manually save state here.
you should use these 2 methods in your app delegate to save current state before entering background/terminate.
- (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.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
}