次の警告に問題があります。
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メッセージからのバックトレースが表示されます。
答えはおそらく私に顔を凝視することですが、多分私はコーヒーを飲み過ぎたのでしょう!
あなたの疑いは正しい。 CoreAnimationの実行が完了する前にNSOperationが完了すると、Nice警告が表示されます。
* 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);
}
}
標準のCocoaパラダイムを維持するための推奨される解決策は、GCDを使用して簡単に行うメインスレッドでコアアニメーションを実行することです。
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate redrawSomething];
});
一般的に、予期しないコンテキストでオブジェクトを呼び出すのは貧弱な形式です。そのため、外部モジュールにメッセージを配信するときに、alwaysメインスレッドにディスパッチすることをお勧めします。
一部のフレームワーク(Core Locationなど)は、メインスレッド以外のコンテキストから呼び出された場合にログメッセージを出力します。他のユーザーは、Core Animationを使用した例のように、不可解なメッセージを出力します。
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:
_の違いに関する関連記事については、 mainqueueのperformSelectorOnMainThreadとdispatch_asyncの違いは? を参照してください。