在iOS模拟器中按下主页按钮时不调用applicationDidEnterBackground和applicationWillEnterForeground方法

时间:2013-03-14 09:26:57

标签: iphone ios5 nstimer nsthread uiapplicationdelegate

我需要在后台和前台完成一项长时间运行的任务。这会更新核心数据。因此,为了维护UI响应,我创建了另一个线程,我使用不同的managedObjectContext(MOC)。因此,计时器在后台和前台设置,并在状态发生变化时被适当地停用。在任务开始之前和任务完成之后,当我按下主页按钮时,它会正确调用两个委托方法但在任务处于活动状态时按下主页按钮屏幕更改并且UI挂起(变为空白)但是两个委托方法不是正确调用,应用程序不会终止。我找不到这种情况发生的原因。如果有人可以提供帮助,那将会很有帮助。

我将附上所需的代码:

-(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];
}

4 个答案:

答案 0 :(得分:18)

在iOS13 +上,如果您实现UIWindowSceneDelegate,则会调用func sceneDidEnterBackground(_ scene: UIScene)

答案 1 :(得分:17)

永远不会调用applicationDidEnterBackground:applicationDidEnterForeground:的原因是因为这些方法与Application does not run in background联合使用,此选项可以在***-info.plist中找到。如果此选项设置为YES,那么您的应用永远不会调用这些方法,因为当您按下主页按钮并将应用选项设置为YES正在运行的应用实例时将被终止,所以每当你按下主页按钮然后选择应用程序图标时,正在创建一个新实例,因此它正在使用applicationWillTerminate:

Kirti mali所说的方法也可能是您使用的不正确的方法,原因是applicationDidBecomeActive:applicationWillResignActive:用于类似于您的时候接听电话。运行的实例不会被终止,也不会被发送到后台。实例暂停,直到用户完成该呼叫时再次激活。

因此,如果您希望应用在后台运行,则解决方法是更改​​Application does not run in background***-info.plist to be applicationDidBecomeActive:中的选项“justand applicationWillResignActive:`是使用这些方法的错误方法。

请参阅UIApplicationDelegate上的苹果文档,以便更好地了解这些方法。

答案 2 :(得分:3)

由于您的应用程序在后台运行,因此这些方法将永远不会调用,但是您可以使用willEnterForegroundNotificationdidEnterBackgroundNotification来完成所需的操作。

您可以在ApplicationDelegate的didFinishLaunchingWithOptions方法内编写以下代码

    NotificationCenter.default.addObserver(forName:UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { (_) in
        // Your Code here
}

NotificationCenter.default.addObserver(forName:UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { (_) in
       // Your Code here        
}

答案 3 :(得分:-1)

按下主页按钮时调用此方法

- (void)applicationDidBecomeActive:(UIApplication *)application

按下图标按钮时调用此方法

- (void)applicationWillResignActive:(UIApplication *)application