ios - 使い方 - layer animation swift




drawViewHierarchyInRect:afterScreenUpdates:他のアニメーションを遅らせる (3)

私のアプリでは、(AppleのUIImageカテゴリUIImageEffectsを使用して)私のビューのぼやけたイメージを取得するために、 drawViewHierarchyInRect:afterScreenUpdates:を使用します。

私のコードは次のようになります:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Use im */

開発中に私のアニメーションの多くが私のアプリをちょっと使った後に遅れていたことに気付きました。つまり、新鮮なアプリの起動に比べて私の見解は目立つ(ただし約2秒未満)一時停止した後です。

いくつかのデバッグの後、私はdrawViewHierarchyInRect:afterScreenUpdates:を使用して画面の更新をYES設定しただけで、この遅延が発生したことに気付きました。 このメッセージがセッションの使用中に送信されなかった場合、遅延は決して現れませんでした。 画面更新パラメータにNOを使用すると、遅延が消えました。

奇妙なことは、このぼかしコードは遅延アニメーション完全に無関係です (私が知る限り)。 問題のアニメーションは、 drawViewHierarchyInRect:afterScreenUpdates: 使用せずCAKeyframeAnimationアニメーションです。 このメッセージを送るという単純な行為(画面の更新がYES設定されている)は、私のアプリで世界的に影響を受けるアニメーションになっているようです。

どうしたの?

(アニメーションの遅延のwithout 、効果を説明するビデオを作成しました。ナビゲーションバーの "Check!"吹き出しの表示の遅れに注意してください)。

更新

この潜在的なバグを説明するためのサンプルプロジェクトを作成しました。 https://github.com/timarnold/AnimationBugExample

更新番号2

私はアップルからこれがバグであることを確認する応答を受けた。 below回答を参照してください。


Appleの開発者サポートチケットの1つを使用してAppleに尋ねました。

確認されたバグです(レーダー番号17851775)。 起こっていることに対する彼らの仮説は以下の通りです。

メソッドdrawViewHierarchyInRect:afterScreenUpdates:可能な限りGPU上で操作を実行しますが、この作業の多くはおそらく別のプロセスのアプリケーションのアドレス空間外で行われます。 afterScreenUpdatesとしてYESを渡す:drawViewHierarchyInRectのパラメータ:afterScreenUpdates:コアアニメーションによって、タスク内とレンダリングタスク内のすべてのバッファがフラッシュされます。 皆さんが想像しているように、このような場合には他にも多くの内部的なものがあります。 エンジニアリングは、あなたが見ている効果に関連するこの機械のバグかもしれないと理論化しています。

これに対して、renderInContextメソッドは、アプリケーションのアドレス空間内で操作を実行し、GPUベースのプロセスを使用して作業を実行しません。 ほとんどの場合、これは別のコードパスであり、それが適切な回避策です。 このルートは、GPUベースのタスクを使用しない場合ほど効率的ではありません。 また、GPUタスクによって管理されるぼやけやその他のCore Animation機能を除外することもできるため、画面キャプチャの精度はあまり高くありません。

また、回避策も提供しました。 彼らは次の代わりにそれを提案した:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Use im */

私はこれを行う必要があります

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Use im */

うまくいけば、これは誰かのために役立ちます!


afterScreenUpdatesパラメータがYESに設定されている場合、システムは、ビューをレンダリングする前にすべての保留中の画面の更新が行われるまで待機する必要があります。

アニメーションを同時に開始している場合は、おそらくレンダリングとアニメーションが同時に発生しようとしている可能性がありますが、これは遅延の原因になります。

これを防ぐために少し後にアニメーションを試して試してみる価値があります。 明らかにそれはオブジェクトを倒すのであまりあまり遅くはないが、小さなdispatch_after間隔は試す価値がある。


バックグラウンドスレッドでコードを実行しようとしましたか? gcdを使った例を紹介します:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    //background thread
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
    [self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
    UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    dispatch_sync(dispatch_get_main_queue(), ^(void) {
        //update ui on main thread
    });
});




core-animation