objective c - Cocoa: bloqueo en_NSDisplayOperationStack; Necesita orientación
objective-c osx (2)
El problema
Recibo informes de fallos de usuarios que se ven así:
Code Type: X86-64 (Native)
Parent Process: launchd [223]
Date/Time: 2012-03-22 11:28:33.087 +0800
OS Version: Mac OS X 10.7.3 (11D50)
Report Version: 9
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: 0x000000000000000d, 0x0000000000000000
VM Regions Near 0:
-->
__TEXT 000000010c202000-000000010c29c000 [ 616K] r-x/rwx SM=COW /Applications/CodeKit.app/Contents/MacOS/CodeKit
Application Specific Information:
objc_msgSend() selector name: release
objc[22113]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff904f5390 objc_msgSend_vtable14 + 16
1 com.apple.Foundation 0x00007fff8f664137 empty + 61
2 com.apple.Foundation 0x00007fff8f666c10 dealloc + 24
3 com.apple.Foundation 0x00007fff8f666bd1 -[NSConcreteMapTable dealloc] + 64
4 com.apple.AppKit 0x00007fff892bc52c -[_NSDisplayOperation dealloc] + 84
5 com.apple.CoreFoundation 0x00007fff8fdc7ca0 CFRelease + 176
6 com.apple.CoreFoundation 0x00007fff8fdf0742 -[__NSArrayM removeObjectAtIndex:] + 434
7 com.apple.AppKit 0x00007fff892bc408 -[_NSDisplayOperationStack exitDisplayOperationForWindow:] + 417
8 com.apple.AppKit 0x00007fff892be2fc -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 7136
9 com.apple.AppKit 0x00007fff892b6429 -[NSView displayIfNeeded] + 1676
10 [SEE DISCUSSION BELOW]
Discusión
Las líneas 10 y siguientes varían ampliamente entre los informes (y, por lo tanto, no están relacionadas con el bloqueo). Sin embargo, la secuencia de las líneas 1 a 9 es siempre la misma. Cada caída contiene esta secuencia exacta. Busqué en Google "_NSDisplayOperationStack" y encontré informes de fallos similares para docenas de aplicaciones (incluidas las conocidas como Omni y Apple''s Motion).
Lo que necesito
Debido a que el accidente proviene de Core Foundation, no tengo idea de dónde comenzar a buscar el problema. Parece estar en el interior de la maquinaria privada de dibujo de vistas de Cocoa. Peor aún, no puedo replicar el bloqueo en mi máquina, así que no puedo rastrearlo con Instruments. Pero he recibido muchos informes con el patrón anterior, así que sé que es un problema. Peor aún, los usuarios ni siquiera pueden reproducir el bloqueo de manera confiable, es completamente intermitente.
Espero que la secuencia anterior le resulte familiar a alguien y que puedan orientarme sobre dónde empezar a buscar el problema. Gracias.
Publiqué esta misma pregunta en los foros de desarrolladores de Apple y un ingeniero me dijo que parecía que el seguimiento de la pila tenía que ver con el dibujo de vistas simultáneas, que es una característica que se introdujo en 10.6.
Revisé todos mis archivos NIB y encontré dos instancias de NSButton que se configuraron para dibujar concurrentemente, esto no fue intencional; Debo haber revisado esa caja por accidente en algún momento.
Inhabilité el dibujo simultáneo para los dos y este accidente desapareció mágicamente.
En algunos casos, deshabilitar el dibujo simultáneo para solo algunos botones no ayuda. Obtuve el mismo error que el del autor ("subdesbordamiento de _NSDisplayOperationStack durante el latido del corazón"). Suerte que hay un interruptor maestro en una ventana que desactiva todos los dibujos concurrentes para una ventana:
[self.window setAllowsConcurrentViewDrawing:NO];
También la apertura de la ventana a través de un bloque ejecutado en la cola principal ayudó:
dispatch_async(dispatch_get_main_queue(), ^{
if(nil == self.someWindowController) {
self.someWindowController = [[[SomeWindowController alloc] initWithWindowNibName:@"SomeWindowController"] autorelease];
}
[self.someWindowController.window makeKeyAndOrderFront:self];
});
Mostrar la ventana desde dentro de un bloque simplemente pospone la ejecución un poco, pero para mi aplicación, una ventana adicional que se abre a través del atajo de menú, una combinación de los dos era lo único que funcionaba.