iphone - ¿Por qué UIBezierPath es más rápido que la ruta de Core Graphics?
ios drawing (1)
Tiene razón en que UIBezierPath
es simplemente un contenedor objetivo-c para Core Graphics, y por lo tanto funcionará de forma comparable. La diferencia (y la razón de su delta de rendimiento) es su estado CGContext
cuando dibujar su CGPath
directamente es bastante diferente a la configuración de UIBezierPath
. Si miras UIBezierPath
, tiene configuraciones para:
-
lineWidth
, -
lineJoinStyle
, -
lineCapStyle
, -
miterLimit
y -
flatness
Al examinar la llamada (desmontaje) a [path stroke]
, observará que configura el contexto gráfico actual en función de esos valores previos antes de realizar la llamada CGContextStrokePath
. Si haces lo mismo antes de dibujar tu CGPath, se realizará de la misma manera:
- (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:
Estaba jugando con dibujar caminos, y noté que en al menos algunos casos, UIBezierPath supera lo que pensé que sería un equivalente de Core Graphics. El método -drawRect:
continuación crea dos rutas: una UIBezierPath y una CGPath. Los caminos son idénticos, excepto por su ubicación, pero acariciar el CGPath toma 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 utilizan CGContextStrokePath (), así que creé métodos separados para recorrer cada ruta, de modo que pueda ver el tiempo utilizado por cada ruta en Instrumentos. A continuación se muestran los resultados típicos (árbol de llamadas invertidas); puedes ver que -strokeContext:
toma 9.5 segundos, mientras que -strokeUIBezierPath:
toma solo 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á de alguna manera optimizando el camino que crea, o estoy creando el CGPath de una manera ingenua. ¿Qué puedo hacer para acelerar mi dibujo de CGPath?