Crash con la versión NSManagedObject: "objc_msgSend () nombre del selector: _queueForDealloc"

He recibido un crash extraño reportado por muchos usuarios a través de HockeyApp con el siguiente rastreo de stack. Parece que tiene algo que ver con que NSManagedObject se lance en una queue de despacho diferente … pero no recibo ninguna simbología de dónde podría estar el problema. Parece un problema de gestión de la memory, pero estoy usando ARC, por lo que no estoy seguro de cómo superaría la liberación de un NSManagedObject.

Este es el informe de locking que obtengo (el hilo principal muestra diferentes rastros en diferentes momentos):

Code Type: ARM-64 Parent Process: launchd [1] Date/Time: 2014-05-12T05:43:54Z OS Version: iPhone OS 7.0.6 (11B651) Report Version: 104 Exception Type: SIGSEGV Exception Codes: SEGV_ACCERR at 0x1c3dbeb8 Crashed Thread: 2 Application Specific Information: objc_msgSend() selector name: _queueForDealloc: Thread 0: 0 CoreFoundation 0x000000018e384618 CFNumberGetType + 0 1 CoreFoundation 0x000000018e3333b8 _CFAppendXML0 + 2768 2 CoreFoundation 0x000000018e333304 _CFAppendXML0 + 2588 3 CoreFoundation 0x000000018e332268 _CFPropertyListCreateXMLData + 196 4 Foundation 0x000000018ef152f4 -[NSDictionary(NSDictionary) writeToFile:atomically:] + 232 5 SimpleList 0x00000001001ae48c __55-[ShanetworkingSettingController writeToContactsReferenceFile]_block_invoke (ShanetworkingSettingController.m:620) 6 libdispatch.dylib 0x000000019a974420 _dispatch_call_block_and_release + 20 7 libdispatch.dylib 0x000000019a9743e0 _dispatch_client_callout + 12 8 libdispatch.dylib 0x000000019a97756c _dispatch_main_queue_callback_4CF + 340 9 CoreFoundation 0x000000018e3e6d64 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8 10 CoreFoundation 0x000000018e3e50a4 __CFRunLoopRun + 1448 11 CoreFoundation 0x000000018e325b38 CFRunLoopRunSpecific + 448 12 GraphicsServices 0x0000000193d4b830 GSEventRunModal + 164 13 UIKit 0x00000001913640e8 UIApplicationMain + 1152 14 SimpleList 0x000000010006347c _mh_execute_header (main.m:18) 15 libdyld.dylib 0x000000019a98faa0 start + 0 Thread 1: 0 libsystem_kernel.dylib 0x000000019aa71ac8 kevent64 + 8 1 libdispatch.dylib 0x000000019a975d78 _dispatch_mgr_thread + 48 Thread 2 Crashed: 0 libobjc.A.dylib 0x000000019a39f9d0 objc_msgSend + 16 1 CoreData 0x000000018e13b284 -[NSManagedObject release] + 168 2 CoreData 0x000000018e131154 -[_PFArray dealloc] + 96 3 libobjc.A.dylib 0x000000019a3a13d4 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 520 4 libdispatch.dylib 0x000000019a97b428 _dispatch_root_queue_drain + 440 5 libdispatch.dylib 0x000000019a97b638 _dispatch_worker_thread2 + 72 6 libsystem_pthread.dylib 0x000000019ab09918 _pthread_wqthread + 352 7 libsystem_pthread.dylib 0x000000019ab097a8 start_wqthread + 0 Thread 3: 0 libsystem_kernel.dylib 0x000000019aa71cc0 mach_msg_trap + 8 1 CoreFoundation 0x000000018e3e6cac __CFRunLoopServiceMachPort + 180 2 CoreFoundation 0x000000018e3e4e3c __CFRunLoopRun + 832 3 CoreFoundation 0x000000018e325b38 CFRunLoopRunSpecific + 448 4 Foundation 0x000000018ef127fc +[NSURLConnection(Loader) _resourceLoadLoop:] + 344 5 Foundation 0x000000018efa0770 __NSThread__main__ + 996 6 libsystem_pthread.dylib 0x000000019ab0c1b0 _pthread_body + 164 7 libsystem_pthread.dylib 0x000000019ab0c108 _pthread_start + 136 8 libsystem_pthread.dylib 0x000000019ab097b0 thread_start + 0 Thread 4: 0 libsystem_kernel.dylib 0x000000019aa8a76c __select + 8 1 libsystem_pthread.dylib 0x000000019ab0c1b0 _pthread_body + 164 2 libsystem_pthread.dylib 0x000000019ab0c108 _pthread_start + 136 3 libsystem_pthread.dylib 0x000000019ab097b0 thread_start + 0 Thread 5: 0 libsystem_kernel.dylib 0x000000019aa8ae74 __workq_kernreturn + 8 1 libsystem_pthread.dylib 0x000000019ab097a8 start_wqthread + 0 Thread 6: 0 libsystem_kernel.dylib 0x000000019aa8ae74 __workq_kernreturn + 8 1 libsystem_pthread.dylib 0x000000019ab097a8 start_wqthread + 0 Thread 7: 0 libsystem_kernel.dylib 0x000000019aa8ae74 __workq_kernreturn + 8 1 libsystem_pthread.dylib 0x000000019ab097a8 start_wqthread + 0 Thread 2 crashed with ARM-64 Thread State: pc: 0x000000019a39f9d0 fp: 0x0000000102b479c0 sp: 0x0000000102b479a0 x0: 0x00000001782451f0 x1: 0x000000018e2eeb56 x2: 0x00000001705336a0 x3: 0x000000019aac3d18 x4: 0x0000000000000001 x5: 0x0000000000000010 x6: 0x000000017013f900 x7: 0x0000000000000000 x8: 0x000000019ad5bdb8 x9: 0x000000001c3dbea8 x10: 0x0000000000000000 x11: 0x000000230000003f x12: 0x000000014f073410 x13: 0xbadd5bcc1c3dbead x14: 0xffffffffffffffff x15: 0x0000000000000001 x16: 0x000000019a39f9c0 x17: 0x000000018e13b1d8 x18: 0x0000000000000000 x19: 0x00000001705336a0 x20: 0x000000019ad7b000 x21: 0x000000019adc9200 x22: 0x000000019ad7b000 x23: 0x0000000000000715 x24: 0x0000000000000010 x25: 0x0000000102a64038 x26: 0xa3a3a3a3a3a3a3a3 x27: 0x0000000000000001 x28: 0x0000000000000000 lr: 0x000000018e13b284 cpsr: 0x0000000020000000 

En el lanzamiento, inicie un par de queues de envío para hacer un trabajo en segundo plano (usan un MOC separado para cargar los objects administrados y procesarlos), para que puedan ser responsables, pero las queues están labeldas en mi aplicación y el seguimiento de stack no parece mostrar qué queue es responsable (si es mi propia queue). He ejecutado la aplicación con NSZombies habilitado, pero eso no ayuda. También ejecuté la herramienta de análisis estático, y eso no muestra nada.

¿Alguna idea de qué podría estar causando este problema, y ​​qué puedo hacer para depurarlo?

EDITAR:

Estoy bastante seguro de que puedo aislar el área del problema a un trozo de código que se llama después de iniciar la aplicación:

 SLAppDelegate *delegate = (SLAppDelegate *) [[UIApplication shanetworkingApplication] delegate]; dispatch_async(delegate.coreDataController.filterMainQueue, ^{ NSManagedObjectContext *backgroundContextImage = [[NSManagedObjectContext alloc] init]; [backgroundContextImage setPersistentStoreCoordinator: delegate.coreDataController.persistentStoreCoordinator]; NSArray *items = [Person getAllPersonsWithContext: backgroundContextImage]; // possibly update some of the items dispatch_async(dispatch_get_main_queue(), ^{ // writes the file inside another dispatch_asyn(dispatch_get_main_queue) [[ShanetworkingSettingController shanetworkingSettings] writeToContactsReferenceFile]; }; }); 

No estoy seguro de qué está mal con esto. Funciona bien el 99% del time. Pero ese 1% está causando algunos lockings que me gustaría resolver.

Llegamos a un problema similar al utilizar un context de object gestionado privado dentro de una NSOperation y terminamos trabajando alnetworkingedor de ella debilitando cualquier parámetro y utilizando un private @autoreleasepool . Elaboraré más adelante.

Nuestra configuration actual tiene un NSOperationQueue que tiene un cálculo de larga duración que hacemos en segundo plano. La operación primero crea un context de object gestionado privado con el set principal como el context del object principal y va y obtiene sus objects.

Mientras tanto, tenemos un NSOperationQueue separado en NSOperationQueue parte que sincroniza nuevos datos de nuestro server, potencialmente agregando, actualizando o eliminando objects usados ​​por nuestra operación de cálculo.

Primero vimos un montón de estos crashs en estado salvaje y la única forma de reprogtwigrlo localmente es hacer que las operaciones de cálculo y synchronization se ejecuten continuamente y después de 5-10 minutos, veríamos un crash similar a uno de los siguientes:

 Thread : Crashed: background queue :: NSOperation 0x18f43c90 0 libobjc.A.dylib 0x36f11f46 objc_msgSend + 5 1 CoreData 0x2928408f -[NSManagedObject release] + 166 2 CoreData 0x2927b4d7 -[_PFArray dealloc] + 94 3 libobjc.A.dylib 0x36f201a9 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 404 4 CoreFoundation 0x294713a9 _CFAutoreleasePoolPop + 16 5 Foundation 0x2a1b6453 -[__NSOperationInternal _start:] + 1058 6 Foundation 0x2a25b44b __NSOQSchedule_f + 186 7 libdispatch.dylib 0x3746d651 _dispatch_queue_drain + 952 8 libdispatch.dylib 0x3746809d _dispatch_queue_invoke + 84 9 libdispatch.dylib 0x3746eba1 _dispatch_root_queue_drain + 320 10 libdispatch.dylib 0x3746fcd7 _dispatch_worker_thread3 + 94 11 libsystem_pthread.dylib 0x375c6e31 _pthread_wqthread + 668 Thread : Crashed: background queue :: NSOperation 0x1db59e80 0 libsystem_kernel.dylib 0x3722edfc __pthread_kill + 8 1 libsystem_pthread.dylib 0x372acd37 pthread_kill + 62 2 libsystem_c.dylib 0x371ce909 abort + 76 3 libsystem_malloc.dylib 0x37258331 szone_size 4 libobjc.A.dylib 0x36bf1621 object_dispose + 20 5 CoreData 0x28ec571d -[_PFManagedObjectReferenceQueue dealloc] + 80 6 CoreData 0x28e5630f -[NSManagedObject dealloc] + 166 7 CoreData 0x28e55217 -[_PFManagedObjectReferenceQueue _queueForDealloc:] + 246 8 CoreData 0x28e5508f -[NSManagedObject release] + 166 9 CoreData 0x28e4c4d7 -[_PFArray dealloc] + 94 10 libobjc.A.dylib 0x36c031a9 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 404 11 CoreFoundation 0x29042149 _CFAutoreleasePoolPop + 16 12 Foundation 0x29d88c23 -[__NSOperationInternal _start:] + 1058 13 Foundation 0x29e2dc1b __NSOQSchedule_f + 186 14 libdispatch.dylib 0x371505b1 _dispatch_queue_drain + 952 15 libdispatch.dylib 0x3714af85 _dispatch_queue_invoke + 84 16 libdispatch.dylib 0x37151b9b _dispatch_root_queue_drain + 338 17 libdispatch.dylib 0x37152cd7 _dispatch_worker_thread3 + 94 18 libsystem_pthread.dylib 0x372a9e31 _pthread_wqthread + 668 Thread : Crashed: NSOperationQueue Serial Queue 0 libsystem_kernel.dylib 0x396871f0 __pthread_kill + 8 1 libsystem_pthread.dylib 0x396ef7b7 pthread_kill + 58 2 libsystem_c.dylib 0x39637ff9 abort + 76 3 libsystem_malloc.dylib 0x396aed25 szone_size 4 libobjc.A.dylib 0x390d93a9 object_dispose + 20 5 CoreData 0x2e3d4081 -[_PFManagedObjectReferenceQueue dealloc] + 80 6 CoreData 0x2e3655b7 -[NSManagedObject dealloc] + 166 7 CoreData 0x2e364501 -[_PFManagedObjectReferenceQueue _queueForDealloc:] + 244 8 CoreData 0x2e36437d -[NSManagedObject release] + 164 9 CoreData 0x2e35b867 -[_PFArray dealloc] + 94 10 libobjc.A.dylib 0x390e20d3 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 358 11 CoreFoundation 0x2e5294c1 _CFAutoreleasePoolPop + 16 12 Foundation 0x2ef29999 -[__NSOperationInternal _start:] + 1064 13 Foundation 0x2efcd745 __NSOQSchedule_f + 60 14 libdispatch.dylib 0x395c0cbd _dispatch_queue_drain + 488 15 libdispatch.dylib 0x395bdc6f _dispatch_queue_invoke + 42 16 libdispatch.dylib 0x395c15f1 _dispatch_root_queue_drain + 76 17 libdispatch.dylib 0x395c18dd _dispatch_worker_thread2 + 56 18 libsystem_pthread.dylib 0x396ecc17 _pthread_wqthread + 298 

Repasamos el código varias veces y no pudimos determinar por qué se queuepsó. Intentamos habilitar NSZombies, pero se quedaría sin memory mucho antes de que pudiéramos get un repro.

Lo que terminamos haciendo es las siguientes 2 cosas:

@autoreleasepool

Dentro de nuestro [privateObjectContext performBlockAndWait:^{…}] que reside dentro de nuestro NSOperationBlock , NSOperationBlock todo el código dentro de un @autoreleasepool{…} . De esa forma, todos los objects gestionados por NSManaged recuperados durante ese bloque de código serán marcados para su publicación antes de abandonar performBlockAndWait.

debilitar / fortalecer

Cualquier parámetro que incluya NSManagedObjects se debilitó antes de pasarlo al bloque, y se fortalece una vez en el bloque. De esta manera, dado que ya no tenemos una fuerte reference a ellos, pueden liberarse si se vuelven desfasados ​​mientras esperamos a que comience la NSOperation . Aquí hay un buen artículo sobre cómo funciona weakify / strongify: http://blog.aceontech.com/post/111694918560/weakifyself-a-more-elegant-solution-to