2012-09-20 22 views
37

estoy teniendo problemas con la siguiente advertencia:advertencia CoreAnimation elimina hilo con CATransaction comprometido

CoreAnimation: advertencia, hilo de suprimirse CATransaction no comprometida; establezca CA_DEBUG_TRANSACTIONS = 1 en el entorno para registrar backtraces.

Estoy usando un objeto NSOperation para realizar algunos cálculos, una vez completado, envía un mensaje de regreso a AppDelegate que luego oculta una barra de progreso y muestra algunos botones. Si vuelvo a comentar el mensaje de regreso a AppDelegate, la advertencia desaparece, pero la barra de progreso obviamente permanece visible y animada.

Estoy usando xCode 4.4.1 y OSX 10.8.1, sin embargo, cuando compilo y ejecuto el código usando la misma versión de xCode en OSX 10.7.4 no recibo la advertencia y el código se ejecuta como se esperaba.

Al establecer la variable de entorno CA_DEBUG_TRANSACTIONS = 1, se muestra la traza inversa como procedente de un mensaje NSControl setEnabled en AppDelegate.

¡La respuesta probablemente me está mirando a la cara, pero tal vez he tomado demasiado café!

+3

He estado jugando con esto un poco hoy. Sospecho que el problema es que NSOperation finaliza antes de que CoreAnimation haya terminado de volver a dibujar los elementos de la interfaz de usuario. La traza inversa mostró que el método originalmente se llamaba desde NSOperation. Intenté implementar una NSNotificación de NSOperation para decirle a AppDelegate que el cálculo está completo, esperando que esto signifique que la NSOperation se puede liberar sin afectar la CoreAnimation, sin embargo, la advertencia sigue ocurriendo pero esta vez la fuente es CoreFoundation. – Milly

+1

En ambos casos, el programa parece funcionar como se esperaba y la advertencia solo se muestra cuando se ejecuta en OS 10.8.1 o 10.8.2 – Milly

Respuesta

18

Sus sospechas son correctas. Si NSOperation se completa antes de que CoreAnimation se ejecute, aparece una bonita advertencia:

* CoreAnimation: advertencia, hilo eliminado con CATransaction no confirmada; establezca CA_DEBUG_TRANSACTIONS = 1 en entorno para registrar backtraces. *

Esto también puede ocurrir en algunas circunstancias cuando un bloque que se distribuye en una cola desencadena algún trabajo de CoreAnimation y regresa antes de que termine CoreAnimation.

La solución que uso es simple: en un bloque o NSOperation que solicita trabajo desde CoreAnimation, compruebo que el trabajo se ha completado antes de salir.

Para darle un ejemplo de prueba de concepto, este es un bloque que se enviará en una cola de despacho. Para evitar la advertencia, verificamos que CoreAnimation esté listo antes de salir.

^{ 

    // 1. Creating a completion indicator 

    BOOL __block animationHasCompleted = NO; 

    // 2. Requesting core animation do do some work. Using animator for instance. 

    [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){ 
     [[object animator] perform-a-nice-animation]; 
    } completionHandler:^{ 
     animationHasCompleted = YES; 
    }]; 

    // 3. Doing other stuff… 

    … 

    // 4. Waiting for core animation to complete before exiting 

    while (animationHasCompleted == NO) 
    { 
     usleep(10000); 
    } 

} 
+3

Esta no es la mejor solución ya que consume recursos innecesarios. Vea a continuación para mejores soluciones. Específicamente, usando 'performSelectorOnMainThread: withObject: waitUntilDone:' o 'dispatch_async()'. – Dalmazio

+0

Esta es una mala solución, todas las animaciones deben enviarse al hilo principal. – PPierson

+3

@PPierson En realidad, las animaciones se envían al hilo principal. No veo qué pasa con la solución. – Jean

24

De acuerdo con los paradigmas de cacao estándar, la solución recomendada aquí es llevar a cabo su trabajo Core Animation en el hilo principal, fácil de hacer con GCD:

dispatch_async(dispatch_get_main_queue(), ^{ 
    [self.delegate redrawSomething]; 
}); 

En general es la falta de forma para llamar a objetos en contextos que no esperan, por lo que una buena regla general es enviar siempre al hilo principal al entregar mensajes a módulos externos.

Algunos marcos, como Core Location, emiten un mensaje de registro si se llaman desde cualquier contexto que no sea el hilo principal. Otros emitirán mensajes crípticos, como su ejemplo aquí con Core Animation.

+1

intenté esto y no funcionó para mí – rbp

8

Otra manera de garantizar cualquier dibujo UI se produce en el hilo principal, como se describe por Numist, está utilizando el método performSelectorOnMainThread:withObject:waitUntilDone: o alternativamente performSelectorOnMainThread:withObject:waitUntilDone:modes:

- (void) someMethod 
{ 
    [...] 

    // Perform all drawing/UI updates on the main thread. 
    [self performSelectorOnMainThread:@selector(myCustomDrawing:) 
          withObject:myCustomData 
         waitUntilDone:YES]; 

    [...] 
} 

- (void) myCustomDrawing:(id)myCustomData 
{ 
    // Perform any drawing/UI updates here. 
} 


Para un post relacionado en la diferencia entre dispatch_async() y performSelectorOnMainThread:withObjects:waitUntilDone: ver Whats the difference between performSelectorOnMainThread and dispatch_async on main queue?

+1

solución simple y buena :) –

Cuestiones relacionadas