ios 为什么 UIBezierPath 比 Core Graphics 路径快?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6327817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is UIBezierPath faster than Core Graphics path?
提问by Caleb
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.
我正在尝试绘制路径,我注意到至少在某些情况下, UIBezierPath 优于我认为的 Core Graphics 等效项。-drawRect:
下面的方法创建了两个路径:一个 UIBezierPath 和一个 CGPath。除了位置不同,这些路径是相同的,但是抚摸 CGPath 所需的时间大约是抚摸 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];
}
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.:
两个路径都使用 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:]
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 正在以某种方式优化它创建的路径,或者我正在以一种天真的方式创建 CGPath。我可以做些什么来加速我的 CGPath 绘图?
回答by Stuart Carnie
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:
您是对的,因为UIBezierPath
它只是 Core Graphics 的 Objective-c 包装器,因此性能相当。差异(以及性能差异的原因)是直接CGContext
绘制时的状态CGPath
与UIBezierPath
. 如果您查看UIBezierPath
,它具有以下设置:
lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
andflatness
lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
和flatness
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:
在检查对 的调用(反汇编)时[path stroke]
,您会注意到它在执行CGContextStrokePath
调用之前根据先前的值配置了当前图形上下文。如果在绘制 CGPath 之前执行相同的操作,它将执行相同的操作:
- (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:
仪器快照: