Ключевая проблема вашего примера в том, что он не оптимизирован. Когда вызывается drawRect:
, устройство рендерит все 1 000 000 квадратов. Хуже того, он делает 6 000 000 вызовов этих API в цикле. Если вы хотите обновить это представление даже со скромными 30 кадрами в секунду, то это 180 000 000 вызовов в секунду.
В вашем «простом» примере размер области рисования составляет 12 000 × 12 000 пикселей; максимальная область, которую вы можете отобразить на дисплее iPad, составляет 768 × 1024 (при условии полноэкранного портрета). Поэтому код тратит много ресурсов ЦП за пределы видимой области . У UIKit есть способы справиться с этим сценарием относительно легко.
При управлении контентом, который значительно больше видимой области, вы должны ограничивать рисование только тем, что является видимым. У UIKit есть несколько способов передать это; UIScrollView в сочетании с видом, поддерживаемым CATiledLayer, - ваш лучший выбор.
Шаги:
Отказ от ответственности: Это определенно оптимизация вашего примера кода выше
- Создание нового приложения для просмотра на основе iPad-проект
- Добавить ссылку на QuartzCore.framework
- Создайте новый класс, скажем
MyLargeView
, подклассами из UIView и добавьте следующий код:
#import <QuartzCore/QuartzCore.h>
@implementation MyLargeView
- (void)awakeFromNib {
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
tiledLayer.tileSize = CGSizeMake(512.0f, 512.0f);
}
// Set the layer's class to be CATiledLayer.
+ (Class)layerClass {
return [CATiledLayer class];
}
- (void)drawRect:(CGRect)rect {
// Drawing code
// only draws what is specified by the rect parameter
CGContextRef context = UIGraphicsGetCurrentContext();
// set up some constants for the objects being drawn
const CGFloat width = 10.0f; // width of rect
const CGFloat height = 10.0f; // height of rect
const CGFloat xSpace = 4.0f; // space between cells (horizontal)
const CGFloat ySpace = 4.0f; // space between cells (vertical)
const CGFloat tWidth = width + xSpace; // total width of cell
const CGFloat tHeight = height + ySpace;// total height of cell
CGFloat xStart = floorf(rect.origin.x / tWidth); // first visible cell (column)
CGFloat yStart = floorf(rect.origin.y / tHeight); // first visible cell (row)
CGFloat xCells = rect.size.width / tWidth + 1; // number of horizontal visible cells
CGFloat yCells = rect.size.height / tHeight + 1; // number of vertical visible cells
for(int x = xStart; x < (xStart + xCells); x++) {
for(int y = yStart; y < (yStart + yCells); y++) {
CGFloat xpos = x*tWidth;
CGFloat ypos = y*tHeight;
CGContextMoveToPoint(context, xpos, ypos);
CGContextAddLineToPoint(context, xpos, ypos + height);
CGContextAddLineToPoint(context, xpos + width, ypos + height);
CGContextAddLineToPoint(context, xpos + width, ypos);
CGContextAddLineToPoint(context, xpos, ypos);
CGContextStrokePath(context);
}
}
}
@end
- Отредактируйте перо контроллера представления и добавьте UIScrollView к представлению
- Добавьте UIView в UIScrollView и убедитесь, что он заполняет UIScrollView
- Изменить класс на MyLargeView
- Установите размер кадра MyLargeView равным 12 000 × 12 000
- Наконец, откройте файл контроллера вида
.m
и добавьте следующее переопределение:
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *scrollView = [self.view.subviews objectAtIndex:0];
scrollView.contentSize = CGSizeMake(12000, 12000);
}
Если вы посмотрите на вызов drawRect:
, он только рисует в область, указанную параметром rect
, что будет соответствовать размеру плитки (512 × 512) для CATiledLayer, который мы настроили в awakeFromNib
метод. Это масштабируется до холста 1 000 000 × 1 000 000 пикселей.
Альтернативные варианты: ScrollViewSuite, пример , в частности 3_Tiling
.