UIKit后台完成任务 - iPhone应用程序崩溃

时间:2011-01-18 16:10:34

标签: iphone objective-c

我正面临一个问题,没有任何解决方案(还)。在用户按下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

更新:似乎与此问题相关的更接近的线程已打开here。 该错误与重定向http连接有关,包括异步和同步NRURL操作。也许,既然NSURLConnection继承了基础框架,那么这个bug也会出现在iPhone上吗?

openradar at:1062401

2 个答案:

答案 0 :(得分: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:' call MUST be ended with endBackgroundTask:'创建的每个后台任务。 仔细检查`endBackgroundTask:'是否使用正确的任务ID调用。

答案 1 :(得分:1)

当后台任务未及时结束时,会导致此异常。虽然我无法100%肯定,但我相信这种特殊的崩溃正在发生,因为你传入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;
}];