applicationDidEnterBackground and applicationWillEnterForeground method are not called when pressed home button in iOS simulator

aparna picture aparna · Mar 14, 2013 · Viewed 20.5k times · Source

I need a long running task to be done in background as well as in foreground. This updates the core data. So to maintain UI responsive I created an another thread where I use different managedObjectContext(MOC). So a timer is set in background as well as in foreground and is inactivated appropriately when state changes. Before the task is starting and after the task is completed when I press home button it calls the two delegate methods properly but during the task is active when I press home button screen changes and UI hangs (becomes blank) but the two delegate methods are not called properly and the app is not terminated. I could not find the reason why this happens so. It would be helpful if someone can help.

I will attach the required code with this :

-(void) startTimerThread
{
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        // Add code here to do background processing
        NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
        [context setPersistentStoreCoordinator:[(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator]];
        self.managedObjectContext = context;
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(mergeChanges:)
                                                     name:NSManagedObjectContextDidSaveNotification
                                                   object:context];
        NSLog(@"managedObjContext : %@\n",self.managedObjectContext);
        [self getDataFromFile];

        dispatch_async( dispatch_get_main_queue(), ^{
            // Add code here to update the UI/send notifications based on the
            // results of the background processing

            [[NSNotificationCenter defaultCenter] postNotificationName:@"ReloadAppDelegateTable" object:nil];
            [context release];
            [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                            name:NSManagedObjectContextDidSaveNotification
                                                          object:context];
        });
    });
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSLog(@"Background\n");
    [self.notificationTimer invalidate];
    self.notificationTimer = nil;
    UIApplication  *app = [UIApplication sharedApplication];
    self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask]; 
        bgTask = UIBackgroundTaskInvalid;
    }];

    //start location update timer and background timer 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:180 target:self
                                                selector:@selector(startLocationServices) userInfo:nil repeats:YES];
    self.locationManager.delegate = self; 
    [self.locationManager startUpdatingLocation]; 

    self.logDownloader.managedObjectContext = self.managedObjectContext;
    NSLog(@"managedObjContext : %@\n",self.logDownloader.managedObjectContext);
    self.backgroundTimer = [NSTimer scheduledTimerWithTimeInterval:90 target:self.logDownloader selector:@selector(getDataFromFile) userInfo:nil repeats:YES];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSLog(@"Foreground\n");
    //invalidate background timer and location update timer
    [self.timer invalidate];
    [self.backgroundTimer invalidate];
    self.timer = nil;
    self.notificationTimer = nil;

    self.logDownloader.managedObjectContext = self.managedObjectContext;
    NSLog(@"managedObjContext : %@\n",self.logDownloader.managedObjectContext);
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ReloadAppDelegateTable" object:nil];

    self.notificationTimer = [NSTimer scheduledTimerWithTimeInterval:180 target:self.logDownloader selector:@selector(startTimerThread) userInfo:nil repeats:YES];
}

Answer

Popeye picture Popeye · Apr 12, 2013

The reason why applicationDidEnterBackground: and applicationDidEnterForeground: are never called is because these methods are used in joint with Application does not run in background this option can be found in your ***-info.plist. If this option is set to YES than your app will never call these methods, because these when you press the home button with an app that has set the option to YES the instance of the app that is running will get terminated so everytime you press the home button and then select the app icon a new instance is being created so it is using applicationWillTerminate:.

The methods that Kirti mali has said would also be the incorrect methods to use for want you are after, the reason being is that applicationDidBecomeActive: and applicationWillResignActive: are used when something like when you answer a phone call. The instance running is not terminated neither is it sent to the background. The instance is paused until the user has finished on that call when it will become active again.

So the solution to this would be if you want the app to run in background would be to change the option "Application does not run in background" in the ***-info.plist to beNOjustapplicationDidBecomeActive:andapplicationWillResignActive:` is the wrong way for these methods to be used.

Please see the apple documentation on UIApplicationDelegate to get a better understanding of these methods.