I am having issues with the following warning:
CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to l
In keeping with standard Cocoa paradigms, the recommended solution here is to perform your Core Animation work on the main thread, easily done with GCD:
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate redrawSomething];
});
In general it's poor form to call objects in contexts they don't expect, so a good rule of thumb is to always dispatch onto the main thread when delivering messages to external modules.
Some frameworks—like Core Location—with emit a log message if they are called from any context other than the main thread. Others will emit cryptic messages, such as your example here with Core Animation.
Your suspicions are right. If NSOperation completes before CoreAnimation is done performing, then you get a nice warning:
*CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.*
This can also happen under some circumstances when a block that is dispatched on a queue triggers some work from CoreAnimation and returns before the CoreAnimation finishes.
The solution I use is simple: On a block or NSOperation that requests work from CoreAnimation, I check that the work has indeed been completed before exiting.
To give you a proof-of-concept example, this is a block to be dispatched on a dispatch queue. In order to avoid the warning, we check that the CoreAnimation is done before exiting.
^{
// 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);
}
}
Another way of ensuring any UI drawing occurs on the main thread, as described by Numist, is using the method performSelectorOnMainThread:withObject:waitUntilDone:
or alternatively 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.
}
For a related post on the difference between dispatch_async()
and performSelectorOnMainThread:withObjects:waitUntilDone:
see Whats the difference between performSelectorOnMainThread and dispatch_async on main queue?