¿Por qué UIBezierPath es más rápido que la ruta Core Graphics?

Estaba jugando con routes de dibujo, y noté que, al less en algunos casos, UIBezierPath supera a lo que creía que sería un Core Graphics equivalente. El método -drawRect: método a continuación crea dos routes: una UIBezierPath y una CGPath. Los paths son idénticos, excepto por sus ubicaciones, pero acariciar el CGPath tarda aproximadamente el doble que acariciar el 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]; } 

Ambas routes usan CGContextStrokePath (), así que he creado methods separados para recorrer cada ruta, de manera que puedo ver el time utilizado por cada ruta en Instrumentos. A continuación se muestran los resultados típicos (tree de llamada invertido); puedes ver que -strokeContext: toma 9.5 seg., mientras que -strokeUIBezierPath: toma solo 5 seg .:

 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:] 

Parece que UIBezierPath está optimizando de alguna manera la ruta que crea, o estoy creando el CGPath de una manera ingenua. ¿Qué puedo hacer para acelerar mi dibujo CGPath?

Tiene razón en que UIBezierPath es simplemente un contenedor objective-c para Core Graphics y, por lo tanto, tendrá un performance comparable. La diferencia (y la razón de su delta de performance) es el estado de CGContext cuando dibujar su CGPath directamente es bastante diferente a la configuration de UIBezierPath . Si miras UIBezierPath , tiene configuraciones para:

  • lineWidth ,
  • lineJoinStyle ,
  • lineCapStyle ,
  • miterLimit y
  • flatness

Al examinar la llamada (desensamblaje) en [path stroke] , observará que configura el context gráfico actual en function de esos valores anteriores antes de realizar la llamada CGContextStrokePath . Si haces lo mismo antes de dibujar tu CGPath, realizará lo mismo:

 - (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]; } 

Instantánea de los instrumentos: Instantánea de instrumentos que muestra el mismo rendimiento