5

I asked about this earlier. I think I phrased my question wrong. Basically I want to save data from my app to a parse backend when the application is terminated. i.e. the app is swiped and killed from the list of apps. iOS documents say that actually applicationDidEnterBackground will be called and NOT applicationWillTerminate so any work can be done in this method.

applicationWillTerminate: For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app. For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.

However this isn't 100% and from my testing applicationDidEnterBackground isn't called every time I quit the app. So how does one save data when an app is terminated with a 100% guarantee it will actually be saved?

This is my code for saving when applicationDidEnterBackground:

- (void)applicationDidEnterBackground:(UIApplication *)application
 {
    bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
        //End the Task
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if([self getController]){                
            CatsViewController *catsViewController = [self getController];
            if(catsViewController.currentUser){                    
                int count = (int)[MyViewController.currentUser.messages count];
                PFInstallation *currentInstallation = [PFInstallation currentInstallation];
                currentInstallation.badge = count;
                [currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                    [application endBackgroundTask:bgTask];
                    bgTask = UIBackgroundTaskInvalid;
                }];                    
            }                
            else{                    
                [application endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
            }
        }            
        else{                
            [application endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
}

Would be great to get any pointers on this. thanks

Kex
  • 8,023
  • 9
  • 56
  • 129
  • 1
    Any reason you can't save on change rather than 'quit' – Wain Jun 25 '15 at 13:46
  • 1
    I'm trying to keep parse in synch with my badge number (the badge number is the number of messages in my app). Rather than make an extra call to parse every single time I delete a message to update the object I would rather do it when the app is put into background or quit with a single call. i.e user opens app deletes 3 messages and then switches app single api call to update the badge count instead of 3. – Kex Jun 25 '15 at 13:51

2 Answers2

5

You could use applicationWillResignActive for things like that. It has the added bonus of being called when the user opens his notification center, too. It will also be called when the user enters the app switcher. If he then kills the app, there is nothing you can do about it, because swiping the app from the switcher will send a SIGKILL. If you are lucky, you can do your background task before that happens by utilizing willResignActive.

I always use applicationWillResignActive and applicationDidBecomeActive respectively, because they both cover a wider range of situations where the app would be not in the foreground.

Also read this answer here (and above)

Community
  • 1
  • 1
assiprinz
  • 101
  • 3
  • Hey thanks for this, so if I move my code to applicationWillResignActive it should do the same thing but also cover me for when in the app switcher right? Was testing a little, because I'm doing a single API call you would have to be super human to swipe quicker than the time it takes to do the call so seems good... – Kex Jun 25 '15 at 16:41
-1

Here's the solution for this. If you swipe to quit your app it will not call the applicationDidEnterBackground because the app terminated. The AppDelegate method to get called when your app is terminated is this method:

1.) You need to add the appWillTerminate observer in you app delegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//This is the observer you need to add so that the applicationWillTerminate app delegate method will get called.
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];

}

2.)Add the codes for saving before your app is terminated.
-(void)applicationWillTerminate:(UIApplication *)application{
//Add your codes like saving data here
}
handiansom
  • 783
  • 11
  • 27
  • applicationWillTerminate is not always called, so this is not a solution. The question clearly states that this method does not work, so what's the reason for posting it? Also there's no reason to make your application listen for UIApplicationWillTerminateNotification since that notification is posted BY applicationWillTerminate. – nickdnk Aug 18 '18 at 14:09