我需要在iPad上绘制50万到100万的多边形。经过实验,我只能获得1 fps。这只是一个例子,我的真实代码有一些大小合适的多边形。
以下是一些问题:
示例drawrect:
//X Y Array of boxes
- (void)drawRect:(CGRect)rect
{
int reset = [self pan].x;
int markX = reset;
int markY = [self pan].y;
CGContextRef context = UIGraphicsGetCurrentContext();
for(int i = 0; i < 1000; i++)//1,000,000
{
for(int j = 0; j < 1000; j++)
{
CGContextMoveToPoint(context, markX, markY);
CGContextAddLineToPoint(context, markX, markY + 10);
CGContextAddLineToPoint(context, markX + 10, markY + 10);
CGContextAddLineToPoint(context, markX + 10, markY);
CGContextAddLineToPoint(context, markX, markY);
CGContextStrokePath(context);
markX+=12;
}
markY += 12;
markX = reset;
}
}
平移只是用平移手势在屏幕上移动框数组。任何帮助或提示都会非常感激。
答案 0 :(得分:18)
您的示例的关键问题是它未经过优化。每当调用drawRect:
时,设备都会渲染所有1,000,000个方格。更糟糕的是,它正在循环中对这些API进行6,000,000次调用。如果你想以一个适度的30fps刷新这个视图,那就是180,000,000次/秒。
使用“简单”示例,绘制区域的大小为12,000px×12,000px;您可以在iPad显示屏上显示的最大区域为768×1024(假设是全屏肖像)。因此,代码在可见区域之外浪费了大量CPU资源。 UIKit可以相对轻松地处理这种情况。
管理明显大于可见区域的内容时,应将绘图限制为仅显示的内容。 UIKit有两种处理方式; UIScrollView与CATiledLayer支持的视图相结合是您最好的选择。
免责声明:这是上述示例代码的优化
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
.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
参数指定的区域,这对应于我们配置的CATiledLayer的区块大小(512×512) awakeFromNib
方法。这将扩展到1,000,000×1,000,000像素画布。
要查看的替代方法是ScrollViewSuite example,特别是3_Tiling
。
答案 1 :(得分:3)
OpenGL是iOS设备上的GPU硬件加速。核心图形绘制不是,并且在处理大量小图形基元(线)时可能要慢很多倍。
对于许多小方块,只需将它们写入C代码中的位图比Core Graphics线条绘制更快。然后只需在完成后将位图绘制到视图中。但Open GL会更快。
答案 2 :(得分:0)
要点4. OpenGL应该可以。检查您是否可以重用这些对象,以及是否可以将某些逻辑移动到GLSL代码。
OpenGL性能优化(在WebGL的上下文中,但大多数应该适用):http://www.youtube.com/watch?v=rfQ8rKGTVlg
答案 3 :(得分:0)
我不知道iOS历史记录的详细信息,因此在首次发布问题时这可能不是一个选项。但是,在处理路径性能问题时,我想将CAShapeLayer称为一个简单的选项。 &#34; iOS核心动画:先进技术&#34; (在Google Books上找到它)说CAShapeLayer&#34;使用硬件加速绘图&#34;我认为这意味着它是基于GPU的实现。同一本书在第6章中有一个很好的用法例子,可以归结为:
通过Instruments测量,这在我的应用程序中产生了巨大的性能差异。如果您的性能问题是基于路径的,那么在您尝试使用CAShapeLayer之前,请不要进入OpenGL。
答案 4 :(得分:0)
我遇到了同样的问题。经过无休止的谷歌搜索,CAShapeLayer终于救了我!以下是您需要执行的详细步骤:
这是一个简单的演示,当您触摸演示视图时绘制一条简单的曲线:
//Simple ShapelayerView.m
-(instancetype)init {
self = [super init];
if (self) {
_bezierPath = [UIBezierPath bezierPath];
CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;
shapeLayer.lineWidth = 5;
shapeLayer.lineJoin = kCALineJoinRound;
shapeLayer.lineCap = kCALineCapRound;
shapeLayer.strokeColor = [UIColor yellowColor].CGColor;
shapeLayer.fillColor = [UIColor blueColor].CGColor;
}
return self;
}
+ (Class)layerClass {
return [CAShapeLayer class];
}
- (void) customDrawShape {
CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;
[_bezierPath removeAllPoints];
[_bezierPath moveToPoint:CGPointMake(10, 10)];
[_bezierPath addQuadCurveToPoint:CGPointMake(2, 2) controlPoint:CGPointMake(50, 50)];
shapeLayer.path = _bezierPath.CGPath;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
[super touchesBegan:touches withEvent:event];
[self customDrawShape];
}