multithreading CoreAnimation 警告删除了带有未提交 CATransaction 的线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12507193/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 01:20:04  来源:igfitidea点击:

CoreAnimation warning deleted thread with uncommitted CATransaction

multithreadingcore-animationnsoperationcatransaction

提问by Milly

I am having issues with the following warning:

我遇到以下警告的问题:

CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.

CoreAnimation:警告,未提交 CATransaction 的已删除线程;在环境中设置 CA_DEBUG_TRANSACTIONS=1 以记录回溯。

I am using an NSOperation object to perform some calculations, once complete it sends a message back to the AppDelegate that then hides a progress bar and unhides some buttons. If I comment out the message back to the AppDelegate the warning goes away but the progress bar obviously remains visible and animated.

我正在使用 NSOperation 对象来执行一些计算,一旦完成它就会向 AppDelegate 发送一条消息,然后隐藏进度条并取消隐藏一些按钮。如果我将消息注释回 AppDelegate 警告消失,但进度条显然保持可见和动画。

I am using xCode 4.4.1 and OSX 10.8.1, however, when I compile and run the code using the same version of xCode on OSX 10.7.4 I do not get the warning and the code runs as expected.

我正在使用 xCode 4.4.1 和 OSX 10.8.1,但是,当我在 OSX 10.7.4 上使用相同版本的 xCode 编译和运行代码时,我没有收到警告并且代码按预期运行。

Setting the CA_DEBUG_TRANSACTIONS=1 environment variable shows the backtrace as coming from an NSControl setEnabled message in the AppDelegate.

设置 CA_DEBUG_TRANSACTIONS=1 环境变量将回溯显示为来自 AppDelegate 中的 NSControl setEnabled 消息。

The answer is probably staring me in the face but maybe I've had too much coffee!

答案可能是盯着我的脸,但也许我喝了太多咖啡!

采纳答案by Jean

Your suspicions are right. If NSOperation completes before CoreAnimation is done performing, then you get a nice warning:

你的怀疑是对的。如果 NSOperation 在 CoreAnimation 执行完成之前完成,那么你会得到一个很好的警告:

*CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.*

*CoreAnimation:警告,已删除未提交 CATransaction 的线程;在环境中设置 CA_DEBUG_TRANSACTIONS=1 以记录回溯。*

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.

在某些情况下,当在队列上调度的块触发 CoreAnimation 的某些工作并在 CoreAnimation 完成之前返回时,也会发生这种情况。

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.

我使用的解决方案很简单:在请求 CoreAnimation 工作的块或 NSOperation 上,我在退出之前检查工作是否确实已完成。

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.

给你一个概念验证的例子,这是一个要在调度队列上调度的块。为了避免警告,我们在退出之前检查 CoreAnimation 是否完成。

^{

   // 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);
   }

}

回答by numist

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:

为了与标准 Cocoa 范例保持一致,这里推荐的解决方案是在主线程上执行 Core Animation 工作,使用 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 alwaysdispatch 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.

如果从主线程以外的任何上下文调用某些框架(例如 Core Location),则会发出日志消息。其他人会发出神秘的消息,例如您在此处使用 Core Animation 的示例。

回答by Dalmazio

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:

确保任何 UI 绘制发生在主线程上的另一种方法,如 Numist 所述,是使用方法performSelectorOnMainThread:withObject:waitUntilDone:或替代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?

有关两者之间区别的相关帖子dispatch_async()performSelectorOnMainThread:withObjects:waitUntilDone:请参阅主队列上 performSelectorOnMainThread 和 dispatch_async 之间的区别是什么?