2012-05-07 11 views
9

私はCoreGraphicsをレンダリングに使用するペイントアプリケーションに取り組んでいます。私の問題は、パフォーマンスのために、変更されたビューの特定の部分のみに更新を制限しようとしています。そのために、私はsetNeedsDisplayInRect:を使用しますが、ビューがコンテンツ全体を更新し、吃音を引き起こすことがあります。これは第3世代のiPadsで特に顕著ですが、シミュレータとiPad2でも発生します。私はこの動作を削除しようとしています。setNeedsDisplayInRect:全体のビューを更新させます

問題を紹介するために、私はXcodeのテンプレートを使って簡単な「単一のビュー」プロジェクトを作成しました。 xibファイルでビューコントローラのビューとして設定したカスタムUIViewサブクラスを作成しました。

のUIViewControllerに追加この:MYVIEW(私のカスタムビュー)へ

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    // Asks that the view refreshes a smal rectangle 
    [self.view setNeedsDisplayInRect:CGRectMake(10, 10, 20, 20)]; 
} 

追加この:

- (void)drawRect:(CGRect)rect 
{ 
    // Just log what is being updated 
    NSLog(@"%@", NSStringFromCGRect(rect)); 
} 

そして、それはそれです。私が3番目のiPad(実際のデバイス)でアプリケーションを実行すると、ログは時々(非常に頻繁に)エントリーで再描画されます。これはとてもイライラしていて、私はアイデアがありません

更新:ここにいくつかのログがあります。時々更新される完全なビューを示しています。私はまた、

2012-05-04 08:34:01.851 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.184 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.197 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.215 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.226 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.242 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.258 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.274 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.290 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.306 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.322 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.338 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.354 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.371 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.387 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.403 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.419 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.439 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.457 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 

私は10Sかそこらと履歴書上のために動いて停止した場合...それは完全に停止させるためにしようとしていますが、どのように理解することはできません、それは間違いなく非常にそれを一貫して行います。

2012-05-04 08:34:33.305 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:33.321 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:35:00.202 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.221 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.234 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.251 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
+0

私の場合、drawRectがsetNeedsDisplayInRectの後に**最初に**呼び出されたとき、rectは完全境界です(私の理由を尋ねません)、次の呼び出しはsetNeedsDisplayInRectのパラメータとして指定されたrectです。タッチの動きを複数回テストしましたか? –

+0

ほとんどの場合、デバイス上で直接発生します。しかし、指を動かしてから約10秒か15秒待ってからタッチしてもう一度動くと、シミュレータ上でそのようにすることができます。 iPad3のデバイスでは、指が動いている間にも起こります。 Sooo annoying :) – mprivat

+0

私は@ thisを投稿しました(http://stackoverflow.com/questions/9299018/setneedsdisplayinrect-bug-in-ios5)。それは最初の呼び出しでしかないようだった。私は原因/修正を見つけたことはなく、そのレベルのパフォーマンス最適化は必要ないので、ただ前進しました。rect == viewのサイズをテストして描画できませんか?おそらくオプションはありません。 –

答えて

5

チェックこのリンゴdocument

は、彼らは言った:

ための方法のiPhone/iPod touchの/ iPadでのUPDAその画面に-setNeedsDisplayInRect:または -setNeedsDisplay:を呼び出すと、 ビュー全体が再描画されます。

また

それぞれのUIViewを単一の要素として扱われます。 -setNeedsDisplayInRect:または-setNeedsDisplay:を呼び出して、一部または全部の再描画を要求すると、ビュー全体に更新のマークが付けられます。

だから、ビュー全体を独立して更新するには、サブビューを使用する必要があると思います。

+1

それは意味をなさない。 2つの方法を持つことのポイントは何でしょうか。それはなぜ時にはうまくいくのですか? – mprivat

+0

私はいくつかのiOS 5のバグを読みました。あなたはiOS 4でそれを試しましたか? –

+0

これは、iOS4のほうがはるかに少ない程度です。 – mprivat

0

私は同様の問題があります。すなわち、setNeedsDisplayInRect:正しいサイズの有効なCGRectを渡す(ブレイクポイントとログで証明された)UIViewの一部のみをsetNeedsDisplayInRectの呼び出しで更新したいとします。 iOS 4.2.1(私のiPhone 3G)では、UIViewは元の画像を保持し、CGRectで指定された部分のみを更新しますが、iOS 5.1(私のiPhone 4S上)ではUIView全体が透過黒で再描画されます透明は私を超えています)、CGRectで指定された領域は正しく描画されます。それは、AppleがsetNeedsDisplayInRectを実装していないというエラーです:正しく、setNeedsDisplay:に渡すだけです。新しいiOSが実際の画面アーキテクチャとのやりとりをどのように処理するかに基づく意思決定だった。いずれにしても、当面は開発者は、グラフィカルな変更が発生するたびにUIView全体を更新するコストをかけなければならないか、iOS検出機能を使用して、対処しているiOSに応じて異なる画面描画コードを実装する必要があります。

私はUIViewプロパティclearsContextBeforeDrawing(ドキュメントに応じて、描画操作を許可する必要があります)でいくつかのテストを行いましたが、結果はYESとNOの両方で同じですので、描画コードの実装と思われます。

更新中に不適切なサイズのCGRectについては、描画呼び出しの前または後に設定されていますか。 setNeedsDisplayInRect:を呼び出す直前にCGRectを設定し、drawRectメソッドの最後の数行でCGRectNullに設定します(drawRectメソッドが呼び出されたシステムで呼び出された場合、私のコードは起動しません)。コードスニペットに戻ると、インラインで設定されていることがわかります。つまり、UIView全体を再描画するシステムコールであり、CGRectが全体のビューである理由です。

私は、AppleがsetNeedsDisplayInRectへの変更の理由を明らかにするか、明らかになったバグを修正するまで、UIViewの内容全体をグラフィカルに更新することを心配しています。更新(潜在的に非常に高価な可能性があります)。

+0

それは私が恐れていたものです。私はアップルと技術サポートチケットをオープンし、彼らは静かにそれを閉じて、言葉を言うことなく私のアカウントにチケットのコストを戻って信じて... – mprivat

13

回答が間違っている(または少なくとも誤解を招く)。

はここsetNeedsDisplayInRectの簡単なコードの例です:私はアップルのドキュメントは、iOSの上のすべてのビューの裏画像がOpenGLのテクスチャに変換されるという事実を説明しようとしていると思われる

http://charcoaldesign.co.uk/resources/chalkboard.zip

:宣伝として活躍します画面全体がフレームごとに再合成されます。これは、ビューのバッキングテクスチャの内容全体をクリアして再描画する必要があるかどうかという問題とは異なります。

setNeedsDisplayInRectを使用すると、フレーム間で変化しないコンテンツ(コアグラフィックスを使用し、ハードウェアアクセラレーションされていない)の高価な再描画を回避できます。画面全体は引き続き再描画されますが、drawRectのコードとは異なり、GPUによってハードウェアアクセラレーションが行われるため、問題はありません。

0

私にはたくさんのデバイスがありませんが、とにかくニュース!何年もiOS上でこの機能を望んでいる人物として、iOS8.0 +がこの機能をもたらすと主張することができます。私は、8.0,8.1,8.2の両方のシミュレータとデバイスで試しました

私はiOS6以降これを試していません。 iOS7で利用できるかどうかは分かりません。多分誰かが確認できるでしょう。

setNeedsDisplayInRect:が文書化されていれば、私と一緒に無事応援してください!

関連する問題