为什么UIBezierPath比Core Graphics路径更快? [英] Why is UIBezierPath faster than Core Graphics path?
问题描述
我正在玩绘图路径,我注意到至少在某些情况下,UIBezierPath优于我认为的Core Graphics等价物。下面的 -drawRect:
方法创建了两个路径:一个UIBezierPath和一个CGPath。除了它们的位置之外,路径是相同的,但是抚摸CGPath所需的时间大约是抚摸UIBezierPath的两倍。
I was playing around with drawing paths, and I noticed that in at least some cases, UIBezierPath outperforms what I thought would be a Core Graphics equivalent. The -drawRect:
method below creates two paths: one UIBezierPath, and one CGPath. The paths are identical except for their locations, but stroking the CGPath takes roughly twice as long as stroking the UIBezierPath.
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create the two paths, cgpath and uipath.
CGMutablePathRef cgpath = CGPathCreateMutable();
CGPathMoveToPoint(cgpath, NULL, 0, 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, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, 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(),所以我创建了单独的方法来描边每条路径这样我就可以看到仪器中每条路径的使用时间。以下是典型结果(呼叫树倒置);你可以看到 -strokeContext:
需要9.5秒,而 -strokeUIBezierPath:
只需要5秒:
Both paths use CGContextStrokePath(), so I created separate methods to stroke each path so that I can see the time used by each path in Instruments. Below are typical results (call tree inverted); you can see that -strokeContext:
takes 9.5 sec., while -strokeUIBezierPath:
takes only 5 sec.:
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绘图速度?
It looks like UIBezierPath is somehow optimizing the path that it creates, or I'm creating the CGPath in a naïve way. What can I do to speed up my CGPath drawing?
推荐答案
你是正确的 UIBezierPath
只是Core Graphics的一个Objective-c包装器,因此性能相当。直接绘制 CGPath
时,差异(以及性能增量的原因)是 CGContext
状态与由 UIBezierPath
设置。如果您查看 UIBezierPath
,它的设置为:
You are correct in that UIBezierPath
is simply an objective-c wrapper for Core Graphics, and therefore will perform comparably. The difference (and reason for your performance delta) is your CGContext
state when drawing your CGPath
directly is quite different to that setup by UIBezierPath
. If you look at UIBezierPath
, it has settings for:
-
lineWidth
, -
lineJoinStyle
, -
lineCapStyle
, -
miterLimit
和 -
平坦度
lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
andflatness
检查电话(反汇编)为 [路径描边]
,您会注意到在执行 CGContextStrokePath
调用之前,它会根据这些先前的值配置当前图形上下文。如果在绘制CGPath之前执行相同的操作,它将执行相同的操作:
When examining the call (disassembly) to [path stroke]
, you will note that it configures the current graphic context based on those previous values before performing the CGContextStrokePath
call. If you do the same prior to drawing your CGPath, it will perform the same:
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create the two paths, cgpath and uipath.
CGMutablePathRef cgpath = CGPathCreateMutable();
CGPathMoveToPoint(cgpath, NULL, 0, 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, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, 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];
}
来自乐器的快照:
Snapshot from Instruments:
这篇关于为什么UIBezierPath比Core Graphics路径更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!