なぜ、iOS 4.3.5 で「大規模な」(960 x 1380) カスタム UIView が CABackingStoreUpdate を非効率的に実行するのですか? また、描画操作のパフォーマンスを改善するにはどうすればよいですか?
私が何を意味するのか完全にはわかりませんか?読む...
ノート:
この問題に対する私の理解が進むにつれて、この質問も進化してきました。その結果、質問自体は似ていますが、次のテキスト本文のコード例と基本的な詳細/推論は、質問が最初に尋ねられてから大幅に変更されました。
環境
カスタム UIView の drawRect: メソッドで 1 つの省略記号を描画する非常に基本的なアプリケーション (下部のコード) があります。このアプリケーションは、描画される楕円のサイズは同じままで、カスタム UIView のサイズが大きくなった場合のパフォーマンスの違いを示しています。
iOS 4.3.5 を実行する iPod 第 4 世代と iOS 5.1.1 を実行する iPad 第 1 世代の両方で、さまざまなサイズのカスタム UIView を使用して一連のアプリケーションを実行しました。
次の表は、時間プロファイラー機器から取得した結果を示しています。
次のインストゥルメント トレースは、各デバイスの両極端の詳細を示しています。
iOS 5.1.1 - (カスタム UIView サイズ 320 x 460)
iOS 5.1.1 - (カスタム UIView サイズ 960 x 1380)
iOS 4.3.5 - (カスタム UIView サイズ 320 x 460)
iOS 4.3.5 - (カスタム UIView サイズ 960 x 1380)
(願わくば) 4 つのケースのうち 3 つのケースでわかるように、期待どおりの結果が得られました。ほとんどの時間は、カスタム UIViews drawRect: メソッドの実行に費やされ、それぞれが 10fps を保持していました。
しかし、4 番目のケースでは、アプリケーションが単一の図形を描画するだけで 7 fps を維持するのに苦労しており、パフォーマンスが低下しています。ほとんどの時間は、UIView の CALayer の表示方法でメモリをコピーするのに費やされました。具体的には次のとおりです。
[CALayer 表示] >
[CALayer _display] >
CABackingStoreUpdate >
CA::Render::ShmemBitmap::copy_pixels(CA::Render::ShmemBitmap const*, CGSRegionObject*) >
memcpy$VARIANT$CortexA8
ここで何か深刻な問題があることを数字から理解するのに、天才は必要ありません。サイズが 960 x 1380 のカスタム UIView を使用すると、iOS 4.3.5 は、ビュー全体のコンテンツを描画するよりも、メモリをコピーするのに 4 倍以上の時間を費やします。
質問
ここで、文脈を考慮して、もう一度質問します。
なぜ、iOS 4.3.5 で「大規模な」(960 x 1380) カスタム UIView が CABackingStoreUpdate を非効率的に実行するのですか? また、描画操作のパフォーマンスを改善するにはどうすればよいですか?
どんな助けでも大歓迎です。
この質問はApple Developer forumsにも投稿しました。
本物
さて、明らかに、この質問のために、実際の問題を最も単純な再現可能なケースに減らしました。私は実際に、UIScrollView 内にある 960 x 1380 のカスタム UIView の一部をアニメーション化しようとしています。
私は、Quartz 2D で望むパフォーマンスのレベルを達成していないときに、OpenGL ES に向けて誰かを誘導する誘惑に感謝しますが、その道をたどる人には、少なくとも、Quartz 2D がパフォーマンスに苦労している理由について説明を提供するようお願いしますiOS 5.1.1 では問題ない iOS 4.3.5 での最も基本的な描画操作。ご想像のとおり、この重要なケースのためにすべてを書き直すという考えには、私は興奮していません。これは、Core Animation の使用を提案する人々にも当てはまります。わかりやすくするために、デモでは色を変える楕円形 (Core Animation に最適なタスク) を使用しましたが、実際に実行したい描画操作は、時間の経過とともに拡大する大量の線、描画タスクです。 Quartz 2D は (パフォーマンスが高い場合に) 理想的です。さらに、もう一度、
コード
TViewController.m (標準ビュー コントローラの実装)
#import "TViewController.h"
#import "TCustomView.h"
// VERSION 1 features the custom UIView the same size as the screen.
// VERSION 2 features the custom UIView nine times the size of the screen.
#define VERSION 2
@interface TViewController ()
@property (strong, nonatomic) TCustomView *customView;
@property (strong, nonatomic) NSTimer *animationTimer;
@end
@implementation TViewController
- (void)viewDidLoad
{
// Custom subview.
TCustomView *customView = [[TCustomView alloc] init];
customView.backgroundColor = [UIColor whiteColor];
#if VERSION == 1
customView.frame = CGRectMake(0.0f, 0.0f, 320.0f, 460.0f);
#else
customView.frame = CGRectMake(0.0f, 0.0f, 960.0f, 1380.0f);
#endif
[self.view addSubview:customView];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[customView addGestureRecognizer:singleTap];
self.customView = customView;
}
#pragma mark - Timer Loop
- (void)handleTap:(UITapGestureRecognizer *)tapGesture
{
self.customView.value = 0.0f;
if (!self.animationTimer || !self.animationTimer.isValid) {
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(animationLoop) userInfo:nil repeats:YES];
}
}
#pragma mark - Timer Loop
- (void)animationLoop
{
// Update model here. For simplicity, increment a single value.
self.customView.value += 0.01f;
if (self.customView.value >= 1.0f)
{
self.customView.value = 1.0f;
[self.animationTimer invalidate];
}
[self.customView setNeedsDisplayInRect:CGRectMake(0.0f, 0.0f, 320.0f, 460.0f)];
}
@end
-
TCustomView.h (カスタム ビュー ヘッダー)
#import <UIKit/UIKit.h>
@interface TCustomView : UIView
@property (assign) CGFloat value;
@end
-
TCustomView.m (カスタム ビューの実装)
#import "TCustomView.h"
@implementation TCustomView
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw ellipses.
CGContextSetRGBFillColor(context, self.value, self.value, self.value, 1.0f);
CGContextFillEllipseInRect(context, rect);
// Draw value itself.
[[UIColor redColor] set];
NSString *value = [NSString stringWithFormat:@"%f", self.value];
[value drawAtPoint:rect.origin withFont:[UIFont fontWithName:@"Arial" size:15.0f]];
}
@end