Низкая производительность с 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.

Другие вопросы по тегам