iOS7应用在后台崩溃

3
我的应用有时在后台运行时会崩溃,并显示以下崩溃日志:
Nov  7 12:33:31 iPad backboardd[29] <Warning>: MyApp[3096] has active assertions beyond permitted time: 
    {(
        <BKProcessAssertion: 0x14680c60> identifier: Called by MyApp, from -[AppDelegate applicationDidEnterBackground:] process: MyApp[3096] permittedBackgroundDuration: 180.000000 reason: finishTask owner pid:3096 preventSuspend  preventIdleSleep  preventSuspendOnSleep 
    )}

浏览其他问题,我发现崩溃信息表明我没有正确结束任务,因此当任务到期时,操作系统会结束它并导致我的应用程序崩溃。

所以我添加了一些NSLog:

- (void)applicationDidEnterBackground:(UIApplication *)application
{       
    [self saveContext];
    [Settings setCallLock:YES];

    [self saveStuff];

    if ([self isBackgroundTaskNeeded]) 
    {

        UIApplication*  app = [UIApplication sharedApplication];

        bgTask = [app beginBackgroundTaskWithExpirationHandler:^{

            [self pauseDownloads];

            NSLog(@"Debug - Ending background task %d",bgTask);
            [app endBackgroundTask:bgTask];
            NSLog(@"Debug -  Background task %d ended",bgTask);
            bgTask = UIBackgroundTaskInvalid;


        }];
        NSLog(@"Debug - Starting background task %d",bgTask);
        [self initBackground];

    }

}

我发现当它崩溃时,这个任务被调用了两次:

Nov  7 12:30:02 iPad MyApp[3096] <Warning>: Debug - Starting background task 7
Nov  7 12:30:30 iPad MyApp[3096] <Warning>: Debug - Starting background task 8
Nov  7 12:33:26 iPad MyApp[3096] <Warning>: Debug - Ending background task 8
Nov  7 12:33:26 iPad MyApp[3096] <Warning>: Debug -  Background task 8 ended
Nov  7 12:33:26 iPad MyApp[3096] <Warning>: Debug - Ending background task 0
Nov  7 12:33:26 iPad MyApp[3096] <Warning>: Debug -  Background task 0 ended

我无法确定双重调用何时发生以及原因。所以问题是为什么任务被调用两次,是否有避免的方法?

编辑:

- (void) pauseDownloads
{
    for (AFDownloadRequestOperation *operation in self.operationQueue.operations)
    {
        if(![operation isPaused])
        {
            [operation pause];
        }
    }
}

你能发布 pauseDownloads 方法吗? - sash
检查您的initBackground方法,在下载完成后结束后台任务。在iOS 7中,最大后台任务时间为3分钟,在iOS 6中约为10分钟。 - sash
2个回答

6

应该在没有过期时间的情况下结束后台任务...

    UIApplication*  app = [UIApplication sharedApplication];

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{

        [self pauseDownloads];

        NSLog(@"Debug - Ending background task %d",bgTask);
        [app endBackgroundTask:bgTask];
        NSLog(@"Debug -  Background task %d ended",bgTask);
        bgTask = UIBackgroundTaskInvalid;


    }];
    NSLog(@"Debug - Starting background task %d",bgTask);

    [self initBackground];

    NSLog(@"Debug - Ending background task %d without expiration",bgTask);
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;

当应用程序进入前台时,请放置此平衡的endBackgroundTask调用 -
- (void)applicationWillEnterForeground:(UIApplication *)application
{
    if (bgTask != UIBackgroundTaskInvalid) {
       NSLog(@"Debug - Ending background task %d without expiration (when applicationWillEnterForeground)",bgTask);
       [app endBackgroundTask:bgTask];
       bgTask = UIBackgroundTaskInvalid;
    }

    // Also, to counter expiration handler pauseDownloads call, consider resuming the downloads here (or applicationDidBecomeActive app delegate).
}

因为 - 当后台任务到达过期时间(通常最多10分钟,但不能保证)时,将会执行过期处理程序block{}。我假设你实际的后台任务是[self initBackground];,否则你应该将它放在块外并在调用endBackgroundTask之前执行。

(另一个潜在问题)

此外,我注意到你现在使用NSOperationQueue来执行下载任务,当应用程序进入后台时。在这种情况下,请确保在下载完成或过期处理程序被执行之前不要调用endBackgroundTask。换句话说,控制不能太早返回,这意味着你可能需要监视这些下载NSOperation(s)。


实际上,这段代码不是我写的,我被指派来修复这个崩溃,而编写它的人已经不在这里工作了,所以我不太确定他的意图,但我相信任务并不是为了尽可能长时间地保持下载运行。 - Leonardo
好的,但这是一个有趣的问题需要修复。我认为你需要至少几个小时来理解和解决它,而不仅仅是几分钟。我建议你尝试在这些NSLog中放置一些时间戳 [NSDate date] 来帮助你调试和理解。请注意 - 据我所知,每个NSOperation都被分叉以在单独的线程中执行,前提是NSOperationQueue没有限制它。当你有空的时候,你可以阅读这个链接 - https://dev59.com/WmIk5IYBdhLWcg3wIq5U#19674292 - Ashok
我会尝试一下,谢谢。关于任务被调用两次的问题,你有什么想法吗? - Leonardo
我刚刚注意到你的日志中有调试时间戳。做一件事,将平衡的 endBackgroundTask 调用放在 applicationWillEnterForeground 委托方法中。看起来这个崩溃只会在应用程序频繁从前台切换到后台时发生!!? - Ashok
是的,这就是崩溃发生的原因,当应用程序频繁从前台切换到后台时,我尝试了您的建议并需要运行更多测试,但似乎已经解决了问题,非常感谢。 - Leonardo
没问题,请随时提出进一步的疑问。这个解决方案可能无法解决所有问题,具体取决于情况。 - Ashok

0
简单来说,你的崩溃是因为你创建了两个后台任务:7 和 8,但只结束了 8。
有了这个知识,你应该应用 Ashok 的解决方案,确保你总是结束任何你创建的后台任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接