Eu estava brincando com o desenho de caminhos e percebi que, pelo menos em alguns casos, o UIBezierPath supera o que eu pensei que seria um equivalente do Core Graphics. O -drawRect:
método a seguir cria dois caminhos: um UIBezierPath e um CGPath. Os caminhos são idênticos, exceto por suas localizações, mas acariciar o CGPath leva aproximadamente o dobro do tempo que acariciar o 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];
}
Ambos os caminhos usam CGContextStrokePath (), então criei métodos separados para traçar cada caminho para que eu possa ver o tempo usado por cada caminho em Instrumentos. Abaixo estão os resultados típicos (árvore de chamadas invertida); você pode ver que -strokeContext:
leva 9,5 segundos, enquanto -strokeUIBezierPath:
leva apenas 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 o UIBezierPath está de alguma forma otimizando o caminho que ele cria, ou estou criando o CGPath de uma forma ingênua. O que posso fazer para acelerar meu desenho CGPath?
UIBezierPath
é um invólucroCGPathRef
. E se você executar ambos, digamos, dez milhões de vezes, e então tirar a média, mas não usar instrumentos, mas doisNSDate
objetos antes e depois das operações.-drawRect:
é chamado algumas dezenas de vezes ou algumas centenas. Eu tentei com até 80.000 segmentos de curva no simulador (muitos para o dispositivo). Os resultados são sempre os mesmos: CGPath leva cerca de duas vezes mais que UIBezierPath, embora ambos usem CGContextStrokePath () para desenhar. Parece claro que o caminho que UIBezierPath constrói é de alguma forma mais eficiente do que aquele que crio com CGPathAddCurveToPoint (). Gostaria de saber como construir caminhos eficientes como o UIBezierPath faz.Respostas:
Você está correto em que
UIBezierPath
é simplesmente um wrapper objetivo-c para Core Graphics e, portanto, terá um desempenho comparável. A diferença (e a razão para seu delta de desempenho) é que seuCGContext
estado ao desenharCGPath
diretamente é bem diferente daquela configuração porUIBezierPath
. Se você olharUIBezierPath
, ele tem configurações para:lineWidth
,lineJoinStyle
,lineCapStyle
,miterLimit
eflatness
Ao examinar a chamada (desmontagem) para
[path stroke]
, você notará que ela configura o contexto gráfico atual com base nos valores anteriores antes de realizar aCGContextStrokePath
chamada. Se você fizer o mesmo antes de desenhar seu CGPath, ele terá o mesmo desempenho:Instantâneo de instrumentos:
fonte