Низкая производительность с CGlayer Drawing
Я использую CGlayers для рисования, как говорится в документации, это более эффективный способ отрисовки рисунка на холсте.
Я в основном рисую в CGlayers и рисую слой в графическом контексте, используя CGContextDrawLayerInRect
Вот мой метод drawRect
- (void)drawRect:(CGRect)rect
{
switch (m_drawStep)
{
case DRAW:
{
CGContextRef context = UIGraphicsGetCurrentContext();//Get a reference to current context(The context to draw)
if(self.currentDrawingLayer == nil)//Potential leak of memory- static analyzer
{
CGFloat scale = self.contentScaleFactor;
CGRect bounds = CGRectMake(0, 0, self.bounds.size.width * scale, self.bounds.size.height * scale);
CGLayerRef layer = CGLayerCreateWithContext(context, bounds.size, NULL);
CGContextRef layerContext = CGLayerGetContext(layer);
CGContextScaleCTM(layerContext, scale, scale);
self.currentDrawingLayer = layer;
}
CGContextRef layerContext = CGLayerGetContext(self.currentDrawingLayer);//Potential leak of memory- static analyzer
CGContextBeginPath(layerContext);
CGContextAddPath(layerContext, mutablePath);
CGContextSetLineWidth(layerContext, self.lineWidth);
CGContextSetStrokeColorWithColor(layerContext, self.lineColor.CGColor);
CGContextSetFillColorWithColor(layerContext, self.lineColor.CGColor);
CGContextSetBlendMode(layerContext,kCGBlendModeNormal);
CGContextStrokePath(layerContext);
CGPathRelease(mutablePath);
CGContextDrawLayerInRect(context, self.bounds, self.currentDrawingLayer );//Potential leak of memory- static analyzer
}
break;
case UNDO:
{
CGContextRef context = UIGraphicsGetCurrentContext();
if(self.currentDrawingLayer == nil)//Potential leak of memory- static analyzer
{
CGFloat scale = self.contentScaleFactor;
CGRect bounds = CGRectMake(0, 0, self.bounds.size.width * scale, self.bounds.size.height * scale);
CGLayerRef layer = CGLayerCreateWithContext(context, bounds.size, NULL);
CGContextRef layerContext = CGLayerGetContext(layer);
CGContextScaleCTM(layerContext, scale, scale);
self.currentDrawingLayer = layer;
}
CGContextRef layerContext1 = CGLayerGetContext(self.currentDrawingLayer );//Potential leak of memory- static analyzer
CGContextClearRect(layerContext1, self.bounds);
for(NSArray *undoArray in m_parentUndoArray)
{
for(int i =0; i<[undoArray count];i++)
{
DrawingPath *drawPath = [undoArray objectAtIndex:i];
CGPathRef path = drawPath.path.CGPath;
mutablePath = CGPathCreateMutableCopy(path);
CGContextBeginPath(layerContext1);
CGContextAddPath(layerContext1, mutablePath);
CGContextSetLineWidth(layerContext1, drawPath.pathWidth.floatValue);
CGContextSetStrokeColorWithColor(layerContext1, drawPath.pathColor.CGColor);
if([drawPath.pathColor isEqual:[UIColor clearColor]])
{
CGContextSetBlendMode(layerContext1,kCGBlendModeClear);
}
else
{
CGContextSetBlendMode(layerContext1,kCGBlendModeNormal);
}
CGContextStrokePath(layerContext1);
CGPathRelease(mutablePath);
}
}
CGContextDrawLayerInRect(context, self.bounds, self.currentDrawingLayer);//Potential leak of memory- static analyzer
}
}
break;
[super drawRect:rect];
}
В функции касания Moved я создаю UIBezeirPath и преобразую его в CGPath.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
self.currentPath = [[DrawingPath alloc] init];
if(m_eraseButtonClicked)
{
[self.currentPath setPathColor:[UIColor clearColor]];
}
else
{
[self.currentPath setPathColor:self.lineColor];
}
CGPathRef cgPath = self.currentPath.path.CGPath;
mutablePath = CGPathCreateMutableCopy(cgPath);
[m_undoArray addObject:self.currentPath];
[self setNeedsDisplay];
}
В касаниях закончились
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[m_parentUndoArray addObject:[NSArray arrayWithArray:m_undoArray]];
}
Проблемы, с которыми я сталкиваюсь ниже
1) Я провел тестирование с помощью профилировщика времени CGContextDrawLayerInRect, который занимает 90% времени при рисовании, поэтому я хочу знать, как мы можем сократить это время, затрачиваемое этим методом, и оптимизировать метод drawRect.
2) Если я нарисую несколько длинных линий и начну постоянно делать отмену / повтор, тогда вы также можете увидеть CGContextDrawLayerInRect, который занимает много времени.
3) Если я удаляю некоторые нарисованные линии и начинаю делать отмены / повторы, еще хуже то, что мое приложение вылетает с предупреждением памяти, я не знаю, что не так с удалением, что оно занимает так много памяти.
Изменить: Код, обновленный, чтобы показать, где статический анализатор говорит, что это проблема памяти
1 ответ
Из моих собственных экспериментов кажется, что iOS иногда будет использовать графический процессор, а иногда и процессор для CGContextDrawLayerInRect, в зависимости от размера копируемого слоя (и, возможно, других факторов). Когда он использует процессор, он в 20 раз медленнее.
Единственное решение - уменьшить размер обновленной области, используя setNeedsDisplayInRect вместо setNeedsDisplay, а также добавив CGContextClipToRect(context, rect) в ваш код drawRect.