AFNetworking在任务上的死锁(tasksForKeyPath)

我确信这是我做的一些愚蠢的事情,但一个小时后我看不到它。 也许你可以。 编辑 :这是在一个设备(iPhone 5S W / iOS 8.4),而不是模拟器。

我有一个DownloadManager的iOS 8应用程序,一个单独的子类使用BackgroundSession的AFHTTPSessionManager。 它曾经工作得很好,但现在我做了一些事情,结果是AFNetworking在setDownloadTaskDidFinishDownloadingBlock死锁,当我引用self.tasks.count

 [self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) { // POINT OF THIS BLOCK: RETURNS A FILENAME URL WHERE THE DOWNLOAD SHOULD GET STORED __strong typeof(self) strongSelf = weakS; if( !strongSelf ) return nil; // deadlocks here on tasks.count DDLogVerbose(@"setDownloadTaskDidFinishDownloadingBlock, start; dataTasks - %lu, downloadTasks - %lu", (unsigned long)strongSelf.dataTaskManager.tasks.count, (unsigned long)strongSelf.tasks.count); 

dataTaskManager引用一个单独的子类AFHTTPSessionManager这是一个标准的会话(不是后台) – 从上面的日志行删除这并不能解决问题。

DownloadManager的completionQueue在init中设置为与DownloadManager使用的所有内容相同的串行队列:

  _processingQueue = dispatch_queue_create([[BUNDLE_IDENTIFIER stringByAppendingString:@".BackgroundSessionManager"] cStringUsingEncoding:NSUTF8StringEncoding], NULL); dispatch_queue_set_specific(_processingQueue, (__bridge const void *)(_processingQueue), (__bridge void *)(_processingQueue), NULL); self.completionQueue = _processingQueue; // set AFNetworking completionQueue to be our queue 

…但这似乎没有帮助。

这是僵局:

我的线程,让我给他们看看你

 (lldb) bt all thread #1: tid = 0x137b14, 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8 frame #1: 0x0000000198958c88 libsystem_kernel.dylib`mach_msg + 72 frame #2: 0x00000001864eb724 CoreFoundation`__CFRunLoopServiceMachPort + 200 frame #3: 0x00000001864e9678 CoreFoundation`__CFRunLoopRun + 940 frame #4: 0x00000001864152d4 CoreFoundation`CFRunLoopRunSpecific + 396 frame #5: 0x000000018fe736fc GraphicsServices`GSEventRunModal + 168 frame #6: 0x000000018b012f40 UIKit`UIApplicationMain + 1488 frame #7: 0x00000001000a60a4 Grab`main(argc=1, argv=0x000000016fd8ba80) + 124 at main.m:14 frame #8: 0x000000019885aa08 libdyld.dylib`start + 4 thread #2: tid = 0x137b6b, 0x0000000198958c24 libsystem_kernel.dylib`kevent64 + 8, queue = 'com.apple.libdispatch-manager' frame #0: 0x0000000198958c24 libsystem_kernel.dylib`kevent64 + 8 frame #1: 0x0000000100496588 libdispatch.dylib`_dispatch_mgr_invoke + 276 frame #2: 0x000000010048709c libdispatch.dylib`_dispatch_mgr_thread + 52 thread #3: tid = 0x137b6c, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8 frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8 frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992 thread #6: tid = 0x137b6f, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8 frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8 frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992 * thread #7: tid = 0x137b97, 0x0000000198958e48 libsystem_kernel.dylib`semaphore_wait_trap + 8, queue = 'NSOperationQueue 0x17022f180 :: NSOperation 0x170449cf0 (QOS: LEGACY)' frame #0: 0x0000000198958e48 libsystem_kernel.dylib`semaphore_wait_trap + 8 frame #1: 0x0000000100494544 libdispatch.dylib`_dispatch_semaphore_wait_slow + 256 * frame #2: 0x000000010018e8f4 Grab`-[AFURLSessionManager tasksForKeyPath:](self=0x0000000127d1e050, _cmd=0x0000000100203d49, keyPath=0x000000017042fdc0) + 340 at AFURLSessionManager.m:617 frame #3: 0x000000010018ee88 Grab`-[AFURLSessionManager tasks](self=0x0000000127d1e050, _cmd=0x0000000191f79785) + 76 at AFURLSessionManager.m:623 frame #4: 0x00000001000a8efc Grab`__36-[DownloadManager loadSessionBlocks]_block_invoke150(.block_descriptor=<unavailable>, session=0x0000000170132700, downloadTask=0x0000000127e408b0, location=0x00000001702bf860) + 328 at DownloadManager.m:149 frame #5: 0x0000000100193734 Grab`-[AFURLSessionManager URLSession:downloadTask:didFinishDownloadingToURL:](self=0x0000000127d1e050, _cmd=0x000000018d2b4ddd, session=0x0000000170132700, downloadTask=0x0000000127e408b0, location=0x00000001702bf860) + 292 at AFURLSessionManager.m:1082 frame #6: 0x0000000185f70b70 CFNetwork`__82-[NSURLSession delegate_downloadTask:didFinishDownloadingToURL:completionHandler:]_block_invoke + 40 frame #7: 0x000000018741b1c4 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16 frame #8: 0x000000018736c604 Foundation`-[NSBlockOperation main] + 96 frame #9: 0x000000018735c1cc Foundation`-[__NSOperationInternal _start:] + 636 frame #10: 0x000000018741df28 Foundation`__NSOQSchedule_f + 228 frame #11: 0x0000000100484f94 libdispatch.dylib`_dispatch_client_callout + 16 frame #12: 0x000000010048fdb8 libdispatch.dylib`_dispatch_queue_drain + 780 frame #13: 0x00000001004882c4 libdispatch.dylib`_dispatch_queue_invoke + 132 frame #14: 0x00000001004925d4 libdispatch.dylib`_dispatch_root_queue_drain + 772 frame #15: 0x0000000100494248 libdispatch.dylib`_dispatch_worker_thread3 + 132 frame #16: 0x0000000198a0d22c libsystem_pthread.dylib`_pthread_wqthread + 816 thread #12: tid = 0x137b9e, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8 frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8 frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992 thread #10: tid = 0x137bf9, 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8, name = 'com.apple.NSURLConnectionLoader' frame #0: 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8 frame #1: 0x0000000198958c88 libsystem_kernel.dylib`mach_msg + 72 frame #2: 0x00000001864eb724 CoreFoundation`__CFRunLoopServiceMachPort + 200 frame #3: 0x00000001864e9678 CoreFoundation`__CFRunLoopRun + 940 frame #4: 0x00000001864152d4 CoreFoundation`CFRunLoopRunSpecific + 396 frame #5: 0x0000000185ef2594 CFNetwork`+[NSURLConnection(Loader) _resourceLoadLoop:] + 440 frame #6: 0x0000000187435db8 Foundation`__NSThread__main__ + 1072 frame #7: 0x0000000198a0fdc8 libsystem_pthread.dylib`_pthread_body + 164 frame #8: 0x0000000198a0fd24 libsystem_pthread.dylib`_pthread_start + 160 thread #11: tid = 0x137bfa, 0x0000000198973498 libsystem_kernel.dylib`__select + 8, name = 'com.apple.CFSocket.private' frame #0: 0x0000000198973498 libsystem_kernel.dylib`__select + 8 frame #1: 0x00000001864f1128 CoreFoundation`__CFSocketManager + 672 frame #2: 0x0000000198a0fdc8 libsystem_pthread.dylib`_pthread_body + 164 frame #3: 0x0000000198a0fd24 libsystem_pthread.dylib`_pthread_start + 160 (lldb) 

…. 我想到了。 由于taskForKeyPath的实现方式,不能像setTaskDidCompleteBlock那样调用。*任务,因为下面的NSURLSession方法(getTasksWithCompletionHandler)会在委托队列上callback,这当然会被setTaskDidCompleteBlock 。 这很糟糕,但我猜,苹果公司的错误,使得任务asynchronous的方法…

所以解决方法是避免从像setTaskDidCompleteBlock(或他们所调用的任何东西)