Почему UIBezierPath быстрее, чем путь Core Graphics?
Я играл с путями рисования и заметил, что, по крайней мере, в некоторых случаях UIBezierPath превосходит то, что я считаю эквивалентом Core Graphics. -drawRect:
Метод ниже создает два пути: один UIBezierPath и один CGPath. Пути идентичны, за исключением их местоположения, но для обхода CGPath требуется примерно вдвое больше, чем для 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];
}
Оба пути используют CGContextStrokePath(), поэтому я создал отдельные методы для обводки каждого пути, чтобы я мог видеть время, используемое каждым путем в Инструментах. Ниже приведены типичные результаты (перевернутое дерево вызовов); ты это видишь -strokeContext:
занимает 9,5 сек., а -strokeUIBezierPath:
занимает всего 5 сек.:
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:]
Похоже, что UIBezierPath каким-то образом оптимизирует путь, который он создает, или я создаю CGPath наивным способом. Что я могу сделать, чтобы ускорить мой рисунок CGPath?
1 ответ
Вы правы в этом UIBezierPath
это просто оболочка Objective-C для Core Graphics, и, следовательно, будет работать сравнительно. Разница (и причина вашей дельты производительности) заключается в вашем CGContext
состояние при рисовании CGPath
напрямую отличается от этой установки UIBezierPath
, Если вы посмотрите на UIBezierPath
, он имеет настройки для:
lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
а такжеflatness
При осмотре вызова (разборки) [path stroke]
вы заметите, что он конфигурирует текущий графический контекст на основе этих предыдущих значений перед выполнением CGContextStrokePath
вызов. Если вы делаете то же самое до рисования вашего CGPath, он будет выполнять то же самое:
- (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];
}
Снимок с инструментов: