为什么UIBezierPath比Core Graphicspath更快?
我正在玩弄绘制path,我注意到,至less在某些情况下,UIBezierPath胜过我认为是Core Graphics等价物。 下面的-drawRect:
方法创build两个path:一个UIBezierPath和一个CGPath。 除了它们的位置之外,path是相同的,但是抚摸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]; }
两个path都使用CGContextStrokePath(),所以我创build了单独的方法来描述每个path,以便我能看到Instruments中每个path使用的时间。 以下是典型的结果(调用树倒置); 你可以看到-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是以某种方式优化它创build的path,或者我以一种天真的方式创buildCGPath。 我能做些什么来加快我的CGPath绘图?
你是正确的,因为UIBezierPath
只是Core Graphics的一个Objective-C包装器,因此可以执行相同的操作。 当你直接绘制CGPath
时,你的CGContext
状态与你的性能增量差异(以及性能差异的原因)与CGPath
设置完全不同。 如果你看UIBezierPath
,它有以下设置:
-
lineWidth
, -
lineJoinStyle
, -
lineCapStyle
, -
miterLimit
和 -
flatness
当检查调用(反汇编)到[path stroke]
,你会注意到它在执行CGContextStrokePath
调用之前,根据这些先前的值configuration当前的graphics上下文。 如果您在绘制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]; }
乐器快照: