0

アプリにカスタム ビュー (から継承UIView) があります。カスタム ビューのオーバーライド

- (void) drawRect:(CGRect) rect

問題はdrawRect:、iPad 2 よりも iPad 3 の方が何倍も長く実行されることです (iPad 3 では約 0.1 秒、iPad 2 では 0.003 秒)。約30倍遅いです。

基本的に、私はいくつかの事前に作成されたレイヤーを使用して、drawRect:. 最後の電話

CGContextDrawLayerAtPoint(context, CGPointZero, m_currentLayer);

ほとんどの時間がかかります ( の合計時間の約 95% drawRect:)

何がそんなに遅くなっているのか、そしてその原因をどのように修正すればよいのでしょうか?

アップデート:

直接関与するスレッドはありません。私はsetNeedsDisplay:あるスレッドを呼び出し、drawRect:別のスレッドから呼び出されますが、それだけです。同じことがロックにも当てはまります (ロックは使用されません)。

タッチに応じてビューが再描画されます (塗り絵アプリです)。iPad 2 では、画面のタッチと更新の間に妥当な遅延が発生します。iPad 3でも同じことを達成したい。

4

2 に答える 2

7

したがって、iPad3は多くの分野で間違いなく遅いです。私はこれについて理論を持っています。 Marco Armentは、この方法renderInContextは新しいiPadでは途方もなく遅いと述べました。カスタムテキストビュー用の虫眼鏡を作成しようとしたときにも、これが当てはまることがわかりました。結局、私はrenderInContextカスタムコアグラフィックスの描画を見送る必要がありました。

私はまた、wait_fencesここで私のコアグラフィックスの描画で恐ろしいエラーを打つ問題を抱えています:新しいiPad 3のみ:wait_fences:応答を受信できませんでした:10004003

これは私がこれまでに理解したことです。iPad3には明らかに4倍のピクセルがあります。これにより、次の2つの場所で問題が発生する可能性があります。

  1. まず、CPU。すべてのコアグラフィックスの描画はCPUによって行われます。回転イベントの場合、CPUの描画に時間がかかりすぎると、wait_fencesエラーが発生します。これは、実際に回転を実行するために少し長く待機するようにデバイスに指示する呼び出しであり、遅延が発生すると思います。
  2. 画像をGPUに転送します。GPUは明らかに網膜の解像度をうまく処理します(Infinity Blade 2を参照)。ただし、コアグラフィックスが描画する場合、memcpyを回避するために、画像をGPUバッファーに直接描画します。ただし、GPUバッファーは、iPad 2以降変更されていないか、バッファーの過負荷が非常に簡単であるため、GPUバッファーを十分に大きくしていません。その場合、CPUは画像を標準メモリに書き込み、GPUバッファが処理できるようになったときにそれらをGPUにコピーすると思います。これがパフォーマンスの問題の原因だと思います。その余分なコピーは非常に多くのピクセルで時間がかかり、物事をかなり遅くします。

memcpyを避けるために、私はいくつかのことをお勧めします:

  1. 必要なものだけを描いてください。画面外に何かを描くことは絶対に避けてください。大きなビューを描画しているが、そのビューの一部(たとえば、それをカバーするサブビュー)のみを表示する場合は、表示されているものだけを描画する方法を見つけてください。
  2. 大きなビューを描画する必要がある場合は、ビューをサブビューまたはサブレイヤー(おそらくあなたの場合はサブレイヤー)としてパーツに分割することを検討してください。そして、必要なものだけを再描画します。注目度の高いアプリを例にとってみましょう。ズームインすると、文字通り一度に1つの正方形が再描画されるのを見ることができます。または、サファリでは、スクロールすると正方形が更新されるのを見ることができます。残念ながら、私はこれを行う必要がなかったので、方法論がわかりません。
  3. 図面はシンプルに保つようにしてください。入力したすべての文字を再描画する必要のある、見栄えの良いカスタムコアテキストビューがありました。非常に遅い。背景をシンプルな白(コアグラフィックス)に変更すると、速度が向上しました。背景を描き直さない方がいいでしょう。

私の理論は推測であるということを指摘したいと思います。Appleは、彼らが何をしているのかを実際には説明していません。私の理論は、彼らが言ったこと、iPadがどのように反応するか、そして私自身の実験に基づいています。

アップデート

そこで、Appleは2012年のWWDC開発者向けビデオをリリースしました。彼らはあなたを助けるかもしれない2つのビデオを持っています(開発者アカウントが必要です):

  1. iOSアプリのパフォーマンス:応答性
  2. iOSアプリのパフォーマンス:グラフィックとアニメーション

彼らが話していることの1つは、あなたがこの方法を使用するのに役立つと思いますsetNeedsDisplayInRect:(CGRect)rect。通常の方法の代わりにこのメソッドを使用し、メソッドが指定されたrectのみを描画するようにすることで、パフォーマンスを大幅に向上させることができますsetNeedsDisplaydrawRect個人的には、次の関数を使用してCGContextClipToRect(context, rect);、提供された四角形にのみ描画をクリップします。

例として、CoreTextを使用してビューに直接テキストを描画するために使用する別のクラスがあります。私のUIViewサブクラスは、このオブジェクトへの参照を保持し、UILabelを使用するのではなく、それを使用してテキストを描画します。setNeedsDisplay以前は、テキストが変更されたときにビュー全体()を更新していました。これで、CoreTextオブジェクトに変更されたCGRectを計算させsetNeedsDisplayInRect、テキストを含むビューの部分のみを変更するために使用します。これは、スクロールするときのパフォーマンスに本当に役立ちました。

于 2012-06-19T14:25:13.357 に答える
1

私は、同様の質問に対して@KurtRevisの回答で説明されているアプローチを使用することになりました。

使用するレイヤーの数を最小限に抑え、追加UIImageViewして、その画像をUIImageラッピングに設定しましたCGImageRef。アプローチの詳細については、上記の回答をお読みください。

結局、私のアプリケーションは以前よりもさらにシンプルになり、iPad2とiPad3でほぼ同じ速度で動作します。

于 2012-06-22T05:21:58.207 に答える