Estaba jugando con trazados de dibujo y noté que, al menos en algunos casos, UIBezierPath supera a lo que pensé que sería un equivalente de Core Graphics. El -drawRect:
método siguiente crea dos rutas: una UIBezierPath y una CGPath. Los caminos son idénticos excepto por sus ubicaciones, pero acariciar el CGPath lleva aproximadamente el doble de tiempo 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 rutas usan CGContextStrokePath (), así que creé métodos separados para trazar cada ruta para poder ver el tiempo usado por cada ruta en Instrumentos. A continuación se muestran los resultados típicos (árbol de llamadas invertido); puedes ver que -strokeContext:
toma 9.5 segundos, mientras que -strokeUIBezierPath:
solo toma 5 segundos:
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 CGPath de una manera ingenua. ¿Qué puedo hacer para acelerar mi dibujo CGPath?
UIBezierPath
es un envoltorio alrededorCGPathRef
. ¿Qué pasa si ejecuta ambos, digamos, diez millones de veces, luego toma el promedio, pero no usa Instrumentos sino dosNSDate
objetos antes y después de las operaciones?-drawRect:
se llama unas pocas docenas de veces o unos cientos. Lo probé con hasta 80000 segmentos de curva en el simulador (demasiados para el dispositivo). Los resultados son siempre aproximadamente los mismos: CGPath tarda aproximadamente el doble que UIBezierPath, aunque ambos usan CGContextStrokePath () para dibujar. Parece claro que la ruta que construye UIBezierPath es de alguna manera más eficiente que la que creo con CGPathAddCurveToPoint (). Me gustaría saber cómo construir rutas eficientes como lo hace UIBezierPath.Respuestas:
Tiene razón en que
UIBezierPath
es simplemente un contenedor de objetivo-c para Core Graphics y, por lo tanto, funcionará de manera comparable. La diferencia (y la razón de su delta de rendimiento) es suCGContext
estado cuando dibuja suCGPath
directamente es bastante diferente a esa configuración porUIBezierPath
. Si mirasUIBezierPath
, tiene configuraciones para:lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
yflatness
Al examinar la llamada (desmontaje) a
[path stroke]
, observará que configura el contexto gráfico actual basándose en esos valores anteriores antes de realizar laCGContextStrokePath
llamada. Si hace lo mismo antes de dibujar su CGPath, realizará lo mismo:Instantánea de instrumentos:
fuente