如何解决为什么UIBezierPath比Core Graphics路径快?
| 我正在研究绘图路径,并且注意到至少在某些情况下,UIBezierPath的性能优于我认为相当于Core Graphics的性能。下面的“ 0”方法创建两条路径:一条UIBezierPath和一条CGPath。路径除了位置外都是相同的,但是抚摸CGPath的时间大约是抚摸UIBezierPath的两倍。- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create the two paths,cgpath and uipath.
CGMutablePathRef cgpath = CGPathCreateMutable();
CGPathMoveToPoint(cgpath,NULL,100);
UIBezierPath *uipath = [[UIBezierPath alloc] init];
[uipath moveToPoint:CGPointMake(0,200)];
// Add 200 curve segments to each path.
int iterations = 200;
CGFloat cgBaseline = 100;
CGFloat uiBaseline = 200;
CGFloat xincrement = self.bounds.size.width / iterations;
for (CGFloat x1 = 0,x2 = xincrement;
x2 < self.bounds.size.width;
x1 = x2,x2 += xincrement)
{
CGPathAddCurveToPoint(cgpath,x1,cgBaseline-50,x2,cgBaseline+50,cgBaseline);
[uipath addCurveToPoint:CGPointMake(x2,uiBaseline)
controlPoint1:CGPointMake(x1,uiBaseline-50)
controlPoint2:CGPointMake(x2,uiBaseline+50)];
}
[[UIColor blackColor] setStroke];
CGContextAddPath(ctx,cgpath);
// Stroke each path.
[self strokeContext:ctx];
[self strokeUIBezierPath:uipath];
[uipath release];
CGPathRelease(cgpath);
}
- (void)strokeContext:(CGContextRef)context
{
CGContextStrokePath(context);
}
- (void)strokeUIBezierPath:(UIBezierPath*)path
{
[path stroke];
}
这两个路径都使用CGContextStrokePath(),因此我创建了单独的方法来描画每个路径,以便可以在Instruments中查看每个路径所用的时间。以下是典型结果(调用树倒置);您可以看到-strokeContext:
需要9.5秒,而-strokeUIBezierPath:
仅需要5秒:
Running (Self) Symbol Name
14638.0ms 88.2% CGContextStrokePath
9587.0ms 57.8% -[QuartzTestView strokeContext:]
5051.0ms 30.4% -[UIBezierPath stroke]
5051.0ms 30.4% -[QuartzTestView strokeUIBezierPath:]
看来UIBezierPath正在某种程度上优化了它创建的路径,或者我正在以一种幼稚的方式创建CGPath。如何加快CGPath绘图速度?
解决方法
没错,“ 5”只是Core Graphics的Objective-C包装器,因此性能相当。区别(和性能差异的原因)是直接绘制
CGPath
时的CGContext
状态与UIBezierPath
的设置完全不同。如果您查看UIBezierPath
,它具有以下设置:
lineWidth
,
lineJoinStyle
,
lineCapStyle
,
miterLimit
和
flatness
在检查对[path stroke]
的调用(反汇编)时,您会注意到,在执行CGContextStrokePath
调用之前,它将基于这些先前的值配置当前图形上下文。如果在绘制CGPath之前执行相同的操作,它将执行相同的操作:
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create the two paths,cgpath and uipath.
CGMutablePathRef cgpath = CGPathCreateMutable();
CGPathMoveToPoint(cgpath,NULL,100);
UIBezierPath *uipath = [[UIBezierPath alloc] init];
[uipath moveToPoint:CGPointMake(0,200)];
// Add 200 curve segments to each path.
int iterations = 80000;
CGFloat cgBaseline = 100;
CGFloat uiBaseline = 200;
CGFloat xincrement = self.bounds.size.width / iterations;
for (CGFloat x1 = 0,x2 = xincrement;
x2 < self.bounds.size.width;
x1 = x2,x2 += xincrement)
{
CGPathAddCurveToPoint(cgpath,x1,cgBaseline-50,x2,cgBaseline+50,cgBaseline);
[uipath addCurveToPoint:CGPointMake(x2,uiBaseline)
controlPoint1:CGPointMake(x1,uiBaseline-50)
controlPoint2:CGPointMake(x2,uiBaseline+50)];
}
[[UIColor blackColor] setStroke];
CGContextAddPath(ctx,cgpath);
// Stroke each path
CGContextSaveGState(ctx); {
// configure context the same as uipath
CGContextSetLineWidth(ctx,uipath.lineWidth);
CGContextSetLineJoin(ctx,uipath.lineJoinStyle);
CGContextSetLineCap(ctx,uipath.lineCapStyle);
CGContextSetMiterLimit(ctx,uipath.miterLimit);
CGContextSetFlatness(ctx,uipath.flatness);
[self strokeContext:ctx];
CGContextRestoreGState(ctx);
}
[self strokeUIBezierPath:uipath];
[uipath release];
CGPathRelease(cgpath);
}
- (void)strokeContext:(CGContextRef)context
{
CGContextStrokePath(context);
}
- (void)strokeUIBezierPath:(UIBezierPath*)path
{
[path stroke];
}
仪器快照:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。