ios - CGlayer 绘图性能低下

标签 ios core-graphics cgcontext cgpath cglayer

我正在使用 CGlayers 进行绘图,如文档所述,这是在 Canvas 上渲染绘图的更有效方式。

我基本上是绘制到 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];
}

在我的 touches 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) 如果我删除一些绘制的线条并开始重复撤消/重做,更糟糕的是,我的应用程序崩溃并显示内存警告,我不知道删除有什么问题,它占用了这么多内存。

编辑:代码,更新以显示静态分析器指出它们是内存问题的地方

最佳答案

根据我自己的实验,iOS 有时会使用 GPU,有时会使用 CPU 来处理 CGContextDrawLayerInRect,这取决于被复制的层的大小(以及可能的其他因素)。当它使用 CPU 时,它会慢 20 倍。

唯一的解决方案是通过使用 setNeedsDisplayInRect 而不是 setNeedsDisplay 来减小更新区域的大小,并在 drawRect 代码中添加 CGContextClipToRect(context, rect)。

关于ios - CGlayer 绘图性能低下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22176467/

相关文章:

objective-c - 图形 - 我如何知道一条线是否在屏幕上可见(考虑到它的宽度)

ios - 在项目 SDK Cocoa Touch Framework 中使用 Firebase Analytics 时崩溃

c# - 如何从 Xamarin 访问 iOS VPN API

ios - 来自不同状态的颜色的 UIButton 背景图像

iphone - 在 CoreGraphics/MapKit 中调试崩溃

ios - 如何使用 CGContextRef 绘制两个单独的形状

iphone - iOS : Core Text - loosing context when drawing image inside a block

iphone - iOS 在命令 Quartz 2D CGContext 上绘图

ios - Firestore iOS - UITableview 中的删除功能

ios - 为什么Xcode7.1不能将1个gestureRecognizer绑定(bind)到2个对象