37

我遇到以下警告的问题:

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

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

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

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

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

4

3 回答 3

24

为了与标准 Cocoa 范例保持一致,这里推荐的解决方案是在主线程上执行核心动画工作,使用 GCD 轻松完成:

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

一般来说,在他们不期望的上下文中调用对象是一种糟糕的形式,所以一个好的经验法则是在向外部模块传递消息时总是调度到主线程。

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

于 2013-06-26T22:05:53.043 回答
19

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

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

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

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

给你一个概念验证的例子,这是一个在调度队列上调度的块。为了避免警告,我们在退出前检查 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);
   }

}
于 2012-11-25T15:36:51.363 回答
9

如 Numist 所述,确保任何 UI 绘制发生在主线程上的另一种方法是使用该方法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.
}


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

于 2013-11-05T01:19:17.920 回答