Why is UIBezierPath faster than Core Graphics?

I played with drawing tracks, and I noticed that, at least in some cases, UIBezierPath is superior to what I considered the equivalent of Core Graphics. The -drawRect: method is described -drawRect: creates two paths: one UIBezierPath and one CGPath. The paths are identical except for their locations, but stroking CGPath takes about twice as much as stroking 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 for each stroke so that I can see the time used by each path in the Tools. Typical results are shown below (inverted call tree); you can see that -strokeContext: takes 9.5 s, and -strokeUIBezierPath: takes only 5 seconds .:

 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 it creates, or I'm creating CGPath in a naive way. What can I do to speed up my CGPath drawing?

+81
ios iphone drawing bezier
Jun 13 2018-11-11T00:
source share
1 answer

You are right that UIBezierPath is just an objective-c wrapper for Core Graphics, and therefore will be comparable. The difference (and the reason for your performance delta) is your CGContext state when drawing your CGPath directly different from this setting using UIBezierPath . If you look at UIBezierPath , it has settings for:

  • lineWidth ,
  • lineJoinStyle ,
  • lineCapStyle ,
  • miterLimit and
  • flatness

When checking a call (disassembly) against [path stroke] you will notice that it will set the current graphics context based on these previous values โ€‹โ€‹before making a call to CGContextStrokePath . If you do the same before drawing CGPath, it will do 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]; } 

Tool shot: Instruments snapshot showing equal performance

+142
Jun 15 '11 at 5:50 a.m.
source share



All Articles