37

次の警告で問題が発生しています。

CoreAnimation:警告、コミットされていないCATransactionを持つスレッドを削除しました。バックトレースをログに記録するには、環境でCA_DEBUG_TRANSACTIONS=1を設定します。

NSOperationオブジェクトを使用していくつかの計算を実行しています。完了すると、メッセージがAppDelegateに返され、進行状況バーが非表示になり、いくつかのボタンが再表示されます。メッセージをAppDelegateにコメントアウトすると、警告は消えますが、進行状況バーは明らかに表示され、アニメーション化されたままになります。

xCode4.4.1とOSX10.8.1を使用していますが、OSX 10.7.4で同じバージョンのxCodeを使用してコードをコンパイルして実行すると、警告が表示されず、コードは期待どおりに実行されます。

CA_DEBUG_TRANSACTIONS = 1環境変数を設定すると、バックトレースがAppDelegateのNSControlsetEnabledメッセージからのものとして表示されます。

答えはおそらく私を顔で見つめていることですが、多分私はコーヒーを飲みすぎたのかもしれません!

4

3 に答える 3

24

標準のCocoaパラダイムに沿って、ここで推奨される解決策は、メインスレッドでCore Animationの作業を実行することです。これは、GCDで簡単に実行できます。

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

一般に、オブジェクトが予期しないコンテキストでオブジェクトを呼び出すのは不適切な形式であるため、外部モジュールにメッセージを配信するときは、常にメインスレッドにディスパッチすることをお勧めします。

コアロケーションなどの一部のフレームワークは、メインスレッド以外のコンテキストから呼び出された場合にログメッセージを出力します。他の人は、ここでのCore Animationの例のように、不可解なメッセージを出力します。

于 2013-06-26T22:05:53.043 に答える
19

あなたの疑惑は正しいです。CoreAnimationの実行が完了する前にNSOperationが完了すると、次のような警告が表示されます。

* 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.
}


の違いに関する関連記事については、メインキューのperformSelectorOnMainThreadとdispatch_asyncの違いは何ですか?dispatch_async()performSelectorOnMainThread:withObjects:waitUntilDone:参照してください。

于 2013-11-05T01:19:17.920 に答える