Je jouais avec des chemins de dessin et j'ai remarqué que dans au moins certains cas, UIBezierPath surpasse ce que je pensais être un équivalent Core Graphics. Le -drawRect:
la méthode ci-dessous crée deux chemins: un UIBezierPath et un CGPath. Les chemins sont identiques à l'exception de leurs emplacements, mais caresser le CGPath prend environ deux fois plus de temps que caresser le 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];
}
Les deux chemins utilisent CGContextStrokePath (), j'ai donc créé des méthodes distinctes pour caresser chaque chemin afin que je puisse voir le temps utilisé par chaque chemin dans Instruments. Voici les résultats typiques (arborescence d'appels inversée); tu peux voir ça -strokeContext:
prend 9,5 secondes, tandis que -strokeUIBezierPath:
ne prend que 5 secondes:
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:]
Il semble que UIBezierPath optimise en quelque sorte le chemin qu'il crée, ou je crée le CGPath de manière naïve. Que puis-je faire pour accélérer mon dessin CGPath?
Vous avez raison en ce que UIBezierPath
est simplement un wrapper objective-c pour Core Graphics, et par conséquent fonctionnera de manière comparable. La différence (et la raison de votre delta de performance) est que votre état CGContext
lorsque vous dessinez directement votre CGPath
est assez différent de celui configuré par UIBezierPath
. Si vous regardez UIBezierPath
, il a des paramètres pour:
lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
etflatness
Lors de l'examen de l'appel (démontage) à [path stroke]
, vous remarquerez qu'il configure le contexte graphique actuel en fonction de ces valeurs précédentes avant d'effectuer l'appel CGContextStrokePath
. Si vous faites de même avant de dessiner votre CGPath, il effectuera la même chose:
- (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];
}
Instantané des instruments: