UIKitBackgroundCompletionTask - iPhone 应用程序崩溃

4

我遇到了一个问题,目前还没有解决方案。我正在使用后台任务处理程序,在用户按下Home按钮后启动一些数据获取。代码类似于:

-(void)startRequest {
    UIApplication *app = [UIApplication sharedApplication];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        dispatch_async(dispatch_get_main_queue(), ^{
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
            });
    }];
    //..
    //Fetch data with NSURLRequest / delegate method
    //..
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    if ([delegate respondsToSelector:delegateErrorMethod])
        [delegate performSelector:delegateErrorMethod];

    UIApplication *app = [UIApplication sharedApplication];
    if (bgTask != UIBackgroundTaskInvalid) {
       dispatch_async(dispatch_get_main_queue(), ^{
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
    }
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if([delegate respondsToSelector:delegateMethod])
        [delegate performSelector:delegateMethod withObject:self];  

    UIApplication *app = [UIApplication sharedApplication];
    if (bgTask != UIBackgroundTaskInvalid) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
    }
}

这个应用程序工作得很好,但有时候(没有任何问题或原因,所以真的很不可预测),会出现以下崩溃日志而导致应用程序崩溃:

Application Specific Information:
MyBackgroundTest[7745] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0x90e65e0> identifier: UIKitBackgroundCompletionTask process: MyBackgroundTest[7745] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:7745 preventSuspend  preventIdleSleep 
)}

Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU 
Elapsed application CPU time (seconds): 0.000, 0% CPU

Thread 0:
0   libSystem.B.dylib               0x33b5d268 mach_msg_trap + 20
1   libSystem.B.dylib               0x33b5f354 mach_msg + 44
2   CoreFoundation                  0x33a48648 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x33a47ed2 __CFRunLoopRun + 350
4   CoreFoundation                  0x33a47c80 CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x33a47b88 CFRunLoopRunInMode + 52
6   GraphicsServices                0x33b0e4a4 GSEventRunModal + 108
7   GraphicsServices                0x33b0e550 GSEventRun + 56
8   UIKit                           0x32099322 -[UIApplication _run] + 406
9   UIKit                           0x32096e8c UIApplicationMain + 664
10  MyBackgroundTest                0x00002d64 0x1000 + 7524
11  MyBackgroundTest                0x00002d18 0x1000 + 7448

Thread 1:
0   libSystem.B.dylib               0x33b89974 kevent + 24
1   libSystem.B.dylib               0x33c33704 _dispatch_mgr_invoke + 88
2   libSystem.B.dylib               0x33c33174 _dispatch_queue_invoke + 96
3   libSystem.B.dylib               0x33c32b98 _dispatch_worker_thread2 + 120
4   libSystem.B.dylib               0x33bd724a _pthread_wqthread + 258
5   libSystem.B.dylib               0x33bcf970 start_wqthread + 0

Thread 2:
0   libSystem.B.dylib               0x33b5d268 mach_msg_trap + 20
1   libSystem.B.dylib               0x33b5f354 mach_msg + 44
2   CoreFoundation                  0x33a48648 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x33a47ed2 __CFRunLoopRun + 350
4   CoreFoundation                  0x33a47c80 CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x33a47b88 CFRunLoopRunInMode + 52
6   WebCore                         0x304df124 RunWebThread(void*) + 332
7   libSystem.B.dylib               0x33bd6886 _pthread_start + 242
8   libSystem.B.dylib               0x33bcba88 thread_start + 0

Thread 3:
0   libSystem.B.dylib               0x33b5d268 mach_msg_trap + 20
1   libSystem.B.dylib               0x33b5f354 mach_msg + 44
2   CoreFoundation                  0x33a48648 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x33a47ed2 __CFRunLoopRun + 350
4   CoreFoundation                  0x33a47c80 CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x33a47b88 CFRunLoopRunInMode + 52
6   Foundation                      0x336465f6 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 206
7   Foundation                      0x33624192 -[NSThread main] + 38
8   Foundation                      0x3361d242 __NSThread__main__ + 966
9   libSystem.B.dylib               0x33bd6886 _pthread_start + 242
10  libSystem.B.dylib               0x33bcba88 thread_start + 0

Thread 4:
0   libSystem.B.dylib               0x33b8168c select$DARWIN_EXTSN + 20
1   CoreFoundation                  0x33a7f662 __CFSocketManager + 582
2   libSystem.B.dylib               0x33bd6886 _pthread_start + 242
3   libSystem.B.dylib               0x33bcba88 thread_start + 0

Thread 5:
0   libSystem.B.dylib               0x33bd79e0 __workq_kernreturn + 8
1   libSystem.B.dylib               0x33bd7364 _pthread_wqthread + 540
2   libSystem.B.dylib               0x33bcf970 start_wqthread + 0

Thread 6:
0   libSystem.B.dylib               0x33bd79e0 __workq_kernreturn + 8
1   libSystem.B.dylib               0x33bd7364 _pthread_wqthread + 540
2   libSystem.B.dylib               0x33bcf970 start_wqthread + 0

Unknown thread crashed with unknown flavor: 5, state_count: 1
更新: 似乎与此问题相关的更接近的线程在这里开放。该错误与重定向http连接有关,包括异步和同步NRURL操作。也许,由于NSURLConnection继承自基础框架,因此iPhone上也存在该错误?

openradar网址:1062401

对我来说,你的应用程序似乎被看门狗定时器杀死了。有可能是url连接挂起时间太长了吗? - Axel
setTimeOutProperty是90秒。据我所知,这是NSURLConnection允许的最长时间。 - valvoline
2个回答

8

我的调查显示,无论原因是什么,你会得到以下异常:

TMS[13544] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0x8cb6040> identifier: UIKitBackgroundCompletionTask process: TMS[13544] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:13544 preventSuspend  preventIdleSleep 
)}

如果代码没有执行`endBackgroundTask:'方法,那么会出现问题。

这意味着使用beginBackgroundTaskWithExpirationHandler:'创建的每个后台任务都必须使用endBackgroundTask:'结束。 请仔细检查是否使用了正确的任务ID调用了`endBackgroundTask:'。


如果您遇到相同的错误,但实际上并没有在任何地方调用beginBackgroundTaskWithExpirationHandler:呢? - AndyDunn
@AndyDunn - 也许你正在包含一个第三方库,它调用了它。 - bandejapaisa
在哪里放置“endBackgroundTask”?我可能正在下载东西,也可能没有,我只是为了防止用户将应用程序移至后台并仍有要下载的内容而使用它。此外,下载不是由委托完成的,因此我必须在另一个类中拥有“endBackgroundTask”。我是否可以设置NSTImer在安全时间后结束后台任务? - subharb
我经常看到这种情况。我个人不会调用beginBackgroundTaskWithExpirationHandler,也没有任何开源的包含库这样做。但是,我不能代表我使用的任何闭源库(广告网络SDK等)。这些或iOS本身的某些部分可能会使用beginBackgroundTaskWithExpirationHandler - Jonny

1
这种异常是由于后台任务未能及时结束引起的。虽然我不能百分之百确定,但我认为此特定崩溃是因为您传递到 beginBackgroundTaskWithExpirationHandler: 的代码块导致的,如果连接仍未完成且系统想要结束您的后台任务,则会调用该代码块。
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    dispatch_async(dispatch_get_main_queue(), ^{
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
}];

- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler的文档介绍了handler: "您应该使用此处理程序来清理并标记后台任务的结束"。

由于dispatch_async调用,当调用此块时,实际上并没有结束任务。在此块调用返回之后(和您的dispatch_async块运行之后),才会结束任务。我认为,在看门狗关闭您的应用程序之前,大多数时间都有足够的时间运行第二个块,但有时候不是这样。因此,您应该立即结束后台任务,然后为任何其他清理需要进行dispatch_async

UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier tid = bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:tid];
    dispatch_async(dispatch_get_main_queue(), ^{
            bgTask = UIBackgroundTaskInvalid;
        });
}];

此外,文档中指出:“处理程序在主线程上同步调用”,因此您实际上没有必要执行dispatch_async。您只需要执行以下操作:
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}];

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