0

I have got requirement in one of my projects where user is asking to save data locally in case of sudden app crashes. Its form based app so user fill lots of data in form and if app crashes suddenly then user lost all data entered.

App is using Core Data to save data locally.

There is a point where we save entered data in core data but not during every second user fills data.

Also if app crashes core data also vanishes.

Mann
  • 5,477
  • 6
  • 45
  • 57
  • This is a bad requirement. The proper requirement would be: fix your bugs so the app doesn't crash. Use unit tests, and automated app testing using Instruments to make sure you don't have crashing bugs. – Kerni Mar 19 '15 at 12:09

4 Answers4

4

In fact, if your app crash, the callback :

- (void)applicationWillTerminate:(UIApplication *)application

will not be called. This one is only called if for some reasons the system need to shutdown your app (usually because resources are rare or because your background job is still doing work after the maximum time allowed) or if you are on < iOs 4. You don't have any way to know when your app will crash (but when you relaunch the app, you can know if it had crashed).

So for your particular case you have two solutions :

  • Use either a NSTimer with a quick firing rate, or call a fonction each time you edit a field and update the core-data context then save it on disk.

    NSError *error = nil;
    [managedObjectContext save:&error]
    

    Did you set a persistentStoreCoordinator on your context ? If no, core-data will never persist your data on disk.

  • Crashes don't appear out of nowhere, find the place(s) where crashes might happen and fix it or if you can't, use a try-catch to keep your app running (but please, try not to do that...).

Hope this help

Aurelien
  • 116
  • 4
  • 2
    This is mostly correct, except the `try-catch` part. This is not a proper handling of issues on iOS, since Exceptions are always fatal and you risk to cause more damage than good! See http://stackoverflow.com/questions/3378696/iphone-try-end-try/3379240#3379240 – Kerni Mar 19 '15 at 12:12
1

In particular case you can should use, try catch block, (but not) everywhere.

try {
   //write your code
}catch(NSException *e){
    //See what's the error
}finally{
    //Save your context
}

This it the best solution in my thinking. However you can create a NSTimer which executes a method at some reasonable seconds where you can hold and save your context.

You can also save your context in AppDelegate's method like (if you're targeting iOS 4.0 and above and if your app was exit by iOS it self for some reason),

- (void)applicationWillTerminate:(UIApplication *)application{};

below method will always call when your app goes in background,

- (void)applicationDidEnterBackground:(UIApplication *)application{};
Hemang
  • 26,840
  • 19
  • 119
  • 186
  • But if app crashes it flushes core data as well. – Mann Mar 19 '15 at 09:52
  • 2
    THIS IS BAD. You should *NOT* use `try catch` everywhere! This is Objective-C and not Java! Exceptions on iOS are always meant to be fatal, read this for more information from a long time Apple employee and developer: http://stackoverflow.com/questions/3378696/iphone-try-end-try/3379240#3379240 – Kerni Mar 19 '15 at 12:05
  • @Kerni, good point, I've updated my answer. Please review it once. Thanks. Please let me know if there's still need some updations. – Hemang Mar 19 '15 at 13:29
1

You can implement a HandleException to catch all exceptions that crash your application.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //for uncaughted exceptions
    NSSetUncaughtExceptionHandler(&HandleException);

    struct sigaction signalAction;
    memset(&signalAction, 0, sizeof(signalAction));
    signalAction.sa_handler = &HandleSignal;

    sigaction(SIGABRT, &signalAction, NULL);
    sigaction(SIGILL, &signalAction, NULL);
    sigaction(SIGBUS, &signalAction, NULL);
    //and more if you need to handle more signals    


    //another setup ...
    return YES
}

#pragma mark crash management
void HandleException(NSException *exception) {
    NSLog(@"[FALTAL] App crashing with exception: %@", exception);
    //try to save your DB here.
}

void HandleSignal(int signal) {
    //try to save your DB here.
}

#pragma -

However, I don't know about how many time you will have before application exits. But I suppose that you will have enough time to do the DB-backup task.

Duyen-Hoa
  • 15,384
  • 5
  • 35
  • 44
  • But if app crashes it flushes core data as well. How can i keep that alive – Mann Mar 19 '15 at 09:52
  • This will not work. They will not be called in case of crashes! – Kerni Mar 19 '15 at 12:03
  • This is even more dangerous! Running any non async-safe code (including any Objective-C code) at crash time has to be avoided at all cost. Read this http://landonf.bikemonkey.org/code/objc/Reliable_Crash_Reporting.20110912.html – Kerni Mar 20 '15 at 14:04
  • I'm not agree that trying to catch a crash and do something is worst than leave our application do nothing when it crashes. It depend on how we implement the HandleException. You can choose not to save your DB context but to the persistent but to some files then try when the application start again, we search for in-progressed works and update the DB. – Duyen-Hoa Mar 20 '15 at 14:19
  • *You can choose not to save your DB context to the persistent* – Duyen-Hoa Mar 20 '15 at 14:28
-1

Use

  • (void)applicationWillTerminate:(UIApplication *)application

delegate method of AppDelgate to save your data in core data.

Abhishek
  • 99
  • 6