AFNetworking deadlock en tareas (tasksForKeyPath)

Estoy seguro de que esto es algo estúpido que estoy haciendo, pero después de una hora no puedo verlo. Tal vez tu puedas. Editar : esto está en un dispositivo (iPhone 5S con iOS 8.4), no en el simulador.

Tengo una aplicación iOS 8 con un DownloadManager, un singleton que subclassa AFHTTPSessionManager utilizando una BackgroundSession. Solía ​​funcionar bien, pero ahora he hecho algo y el resultado es que los interlockings setDownloadTaskDidFinishDownloadingBlock en setDownloadTaskDidFinishDownloadingBlock , cuando hago reference a 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 hace reference a un AFHTTPSessionManager subclasificado por separado, que es una session estándar (no en segundo plano); eliminarlo de la línea de logging anterior no soluciona el problema.

DownloadManager's completionQueue se establece en init para ser la misma queue de serie que el DownloadManager usa para todo:

  _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 

… pero eso no parece ayudar.

Aquí está el punto muerto:

Mis hilos, déjame mostrártelos

 (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) 

…. Me lo imaginé. Debido a la forma en que se implementa tasksForKeyPath, no es posible llamar a tareas * desde los bloques como setTaskDidCompleteBlock, porque el método NSURLSession debajo (getTasksWithCompletionHandler) devolverá la llamada a la queue de delegates, que por supuesto está bloqueado por el bloque original como setTaskDidCompleteBlock . Esto es una mierda, pero es un error de Apple, creo, para hacer que el método que hace las tareas asíncronas …

Por lo tanto, la solución es evitar que las tareas actuales provengan de bloques como setTaskDidCompleteBlock (o cualquier cosa que llamen)