Ich habe mit dem Zeichnen von Pfaden herumgespielt und festgestellt, dass UIBezierPath in einigen Fällen besser ist als das, was ich für ein Core Graphics-Äquivalent gehalten habe. Das -drawRect:
Methode unten erstellt zwei Pfade: einen UIBezierPath und einen CGPath. Die Pfade sind bis auf die Position identisch, das Zeichnen des CGPath dauert jedoch ungefähr doppelt so lange wie das Zeichnen des 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];
}
Beide Pfade verwenden CGContextStrokePath (). Daher habe ich separate Methoden zum Strichzeichnen der einzelnen Pfade erstellt, sodass die von den einzelnen Pfaden in Instruments verwendete Zeit angezeigt wird. Nachfolgend finden Sie typische Ergebnisse (Anrufbaum invertiert). Sie können sehen, dass -strokeContext:
dauert 9,5 Sek., während -strokeUIBezierPath:
dauert nur 5 sek .:
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:]
Es sieht so aus, als würde UIBezierPath den Pfad, den es erstellt, irgendwie optimieren, oder ich erstelle den CGPath auf naive Weise. Was kann ich tun, um mein CGPath-Zeichnen zu beschleunigen?
Sie haben Recht, dass UIBezierPath
einfach ein Objective-C-Wrapper für Core Graphics ist und daher eine vergleichbare Leistung erbringt. Der Unterschied (und der Grund für Ihr Leistungsdelta) ist Ihr CGContext
- Status, wenn Sie Ihr CGPath
direkt zeichnen, unterscheidet sich erheblich von dem von UIBezierPath
. Wenn Sie sich UIBezierPath
ansehen, hat es Einstellungen für:
lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
undflatness
Bei der Prüfung des Aufrufs (Demontage) an [path stroke]
, Sie werden feststellen, dass der aktuelle Grafikkontext basierend auf diesen vorherigen Werten konfiguriert wird, bevor der Aufruf CGContextStrokePath
ausgeführt wird. Wenn Sie vor dem Zeichnen Ihres CGPath dasselbe tun, wird dasselbe ausgeführt:
- (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];
}
Schnappschuss von Instrumenten: