Ich habe mit Zeichenpfaden herumgespielt und festgestellt, dass UIBezierPath zumindest in einigen Fällen das übertrifft, was ich für ein Core Graphics-Äquivalent hielt. Die folgende -drawRect:
Methode erstellt zwei Pfade: einen UIBezierPath und einen CGPath. Die Pfade sind bis auf ihre Position identisch, aber das Streicheln des CGPath dauert ungefähr doppelt so lange wie das Streichen 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 erstellt, um jeden Pfad zu streicheln, damit ich die von jedem Pfad in Instruments verwendete Zeit sehen kann. Nachfolgend sind typische Ergebnisse aufgeführt (Aufrufbaum invertiert). Sie können sehen, dass dies -strokeContext:
9,5 Sekunden -strokeUIBezierPath:
dauert , während es nur 5 Sekunden dauert:
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 von ihm erstellten Pfad irgendwie optimieren, oder ich erstelle den CGPath auf naive Weise. Was kann ich tun, um meine CGPath-Zeichnung zu beschleunigen?
UIBezierPath
ist ein Wrapper herumCGPathRef
. Was ist, wenn Sie beide ausführen, sagen wir zehn Millionen Mal, und dann den Durchschnitt nehmen, aber keine Instrumente verwenden, sondern zweiNSDate
Objekte vor und nach den Operationen.-drawRect:
sie ein paar Dutzend Mal oder ein paar Hundert Mal aufgerufen werden. Ich habe es mit bis zu 80000 Kurvensegmenten auf dem Simulator versucht (viel zu viele für das Gerät). Die Ergebnisse sind immer ungefähr gleich: CGPath dauert ungefähr doppelt so lange wie UIBezierPath, obwohl beide CGContextStrokePath () zum Zeichnen verwenden. Es scheint klar zu sein, dass der Pfad, den UIBezierPath erstellt, irgendwie effizienter ist als der, den ich mit CGPathAddCurveToPoint () erstellt habe. Ich möchte wissen, wie man effiziente Pfade wie UIBezierPath erstellt.Antworten:
Sie haben Recht damit, dass
UIBezierPath
es sich lediglich um einen Objective-C-Wrapper für Core Graphics handelt und daher eine vergleichbare Leistung erbringt. Der Unterschied (und der Grund für Ihr Leistungsdelta) ist IhrCGContext
Status beimCGPath
direkten Zeichnen , der sich erheblich von dem von unterscheidetUIBezierPath
. Wenn Sie sich ansehenUIBezierPath
, hat es Einstellungen für:lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
undflatness
Wenn Sie den Aufruf (Demontage) untersuchen
[path stroke]
, werden Sie feststellen, dass der aktuelle grafische Kontext basierend auf diesen vorherigen Werten konfiguriert wird, bevor derCGContextStrokePath
Aufruf ausgeführt wird. Wenn Sie vor dem Zeichnen Ihres CGPath dasselbe tun, wird dasselbe ausgeführt:Schnappschuss von Instrumenten:
quelle