1

I am working CGlayers for drawing. I have implemented the drawing part, the drawingView(canvas) where the user will draw is dynamic, what I mean by this is, user can increase/decrease height of the drawingView(Canvas)

For example by default size - 500*200

When user clicks on expand button - 500*300

So here is my function when user expands the canvas,

- (void)IncreaseCanavasSize
{
    CGContextRef layerContext1 = CGLayerGetContext(permanentDrawingLayer );
    CGContextDrawLayerInRect(layerContext1, rectSize, newDrawingLayer);

    rectSize = self.bounds;

    CGFloat scale = self.contentScaleFactor;
    CGRect bounds = CGRectMake(0, 0, self.bounds.size.width * scale, self.bounds.size.height * scale);
    CGLayerRef layer = CGLayerCreateWithContext(layerContext1, bounds.size, NULL);
    CGContextRef layerContext = CGLayerGetContext(layer);
    CGContextScaleCTM(layerContext, scale, scale);
    [self setNewDrawingLayer:layer];
    CGLayerRelease(layer);         

   CGContextDrawLayerInRect(layerContext, self.bounds, permanentDrawingLayer);
        permanentDrawingLayer = nil;
}

So let me explain what I am doing in the above code, I am creating a newLayer with size before it is increased, and then transfer the previousDrawing from "*permanentDrawingLayer" to this "newDrawingLayer" and making "permanentDrawing" nil*

So Whenever I draw, I draw into permanentDrawingLayer, here is my drawRect method

- (void)drawRect:(CGRect)rect
{

   if(permanentDrawingLayer == nil)
   {
        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 setPermanentDrawingLayer:layer];
         CGLayerRelease(layer);
   }


   CGContextRef layerContext = CGLayerGetContext(permanentDrawingLayer);
   CGContextBeginPath(layerContext);
   CGContextAddPath(layerContext, mutablePath);
   CGContextSetLineWidth(layerContext, self.lineWidth);
   CGContextSetLineCap(layerContext, kCGLineCapRound);
   CGContextSetLineJoin(layerContext, kCGLineJoinRound);
   CGContextSetAllowsAntialiasing(layerContext, YES);
   CGContextSetShouldAntialias(layerContext, YES);
   CGContextSetStrokeColorWithColor(layerContext, self.lineColor.CGColor);
   CGContextSetFillColorWithColor(layerContext, self.lineColor.CGColor);
   CGContextSetBlendMode(layerContext,kCGBlendModeNormal);
   CGContextStrokePath(layerContext);

   CGContextDrawLayerInRect(context,rectSize, newDrawingLayer);
   CGContextDrawLayerInRect(context, self.bounds, permanentDrawingLayer);
}

Here you can see, I draw newDrawingLayer with rectSize, and permanetDrawingLayer with newSize, So whenever, I draw on a canvas, if user has increased the size, the newDrawingLayer will draw that, and new drawing whatever user does will be done in permanentDrawingLayer. Hope it is clear.

Now here are my problems

1) Memory spikes to 10MB, when I drawSomething and increase the canvasSize, so if I do this action always you can imagine, how fast my app will terminate due to memory pressure.

2) What I saw was if I comment the Line " permanentDrawingLayer = nil" in function - "IncreaseCanavasSize", then memory doesnt spikes up, but if I dont do that, then when I draw next time, then Layer with newSize will not be created and I will get duplicate drawings.

So I need all your help

Ranjit
  • 4,576
  • 11
  • 62
  • 121

1 Answers1

1

Your permanentDrawingLayer is a CGLayerRef so setting it to NULL, don't release it. You need to call CGLayerRelease(permanentDrawingLayer) before setting it to NULL.

- (void)IncreaseCanavasSize
{
     CGContextRef layerContext1 = CGLayerGetContext(permanentDrawingLayer );
     CGContextDrawLayerInRect(layerContext1, rectSize, newDrawingLayer);

     rectSize = self.bounds;

     CGFloat scale = self.contentScaleFactor;
     CGRect bounds = CGRectMake(0, 0, self.bounds.size.width * scale, self.bounds.size.height * scale);
     CGLayerRef layer = CGLayerCreateWithContext(layerContext1, bounds.size, NULL);
     CGContextRef layerContext = CGLayerGetContext(layer);
     CGContextScaleCTM(layerContext, scale, scale);
    [self setNewDrawingLayer:layer];
     CGLayerRelease(layer);         

     CGContextDrawLayerInRect(layerContext, self.bounds, permanentDrawingLayer);

    CGLayerRelease(permanentDrawingLayer);
    permanentDrawingLayer = NULL;
}

Also if your method -setPermanentDrawingLayer: looks like the method -setCurrentDrawingLayer: in your previous question. In -IncreaseCanavasSize You can simply replace the line permanentDrawingLayer = nil; with [self setPermanentDrawingLayer:NULL];, then it will release the CGLayerRef and set it to NULL.

Community
  • 1
  • 1
Emmanuel
  • 2,897
  • 1
  • 14
  • 15
  • Hello @Emmanuel, what is the difference between releasing and setting it to Nil? – Ranjit Mar 19 '14 at 13:16
  • So if I do just [self setPermanentDrawingLayer:NULL]; then their is no need to to do two steps like first release and then setting it to null right? – Ranjit Mar 19 '14 at 13:18
  • @Ranjit If `-setPermanentDrawingLayer:` is implemented in the way `-setCurrentDrawingLayer:` was, yes. – Emmanuel Mar 19 '14 at 13:22
  • Yes, it is, thanks a lot, Emmanuel, you made my day, Please also tell me why the memory spike was so much and what is the difference between just making it NULL and first releasing and then making it NULL. – Ranjit Mar 19 '14 at 13:27
  • With CoreFoundation you need to deallocate the objects you create. (CoreFoundation objects are not handled by ARC.) Just setting `permanentDrawingLayer` to NULL don't deallocate it, you just lose the pointer to the object created, so you can never deallocate it properly (memory leak). You should take a look to [Memory Management Programming Guide for Core Foundation](https://developer.apple.com/library/mac/documentation/corefoundation/Conceptual/CFMemoryMgmt/CFMemoryMgmt.html) – Emmanuel Mar 19 '14 at 15:08