Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop drawing of CATiledLayer

Is is possible to stop CATiledLayer to draw (drawLayer:inContext)? It draws asynchronously and when i try to release CGPDFDocumentRef, which is used by CATiledLayer, the app crashes (EXC_BAD_ACCESS).

That's my view:

@implementation TiledPDFView

- (id)initWithFrame:(CGRect)frame andScale:(CGFloat)scale{
    if ((self = [super initWithFrame:frame])) {

        CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
        tiledLayer.levelsOfDetail = 4;
        tiledLayer.levelsOfDetailBias = 4;
        tiledLayer.tileSize = CGSizeMake(512.0, 512.0);
        myScale = scale;
    }
    return self;
}

// Set the layer's class to be CATiledLayer.
+ (Class)layerClass {
    return [CATiledLayer class];
}

- (void)stopDrawing{
    CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
    [tiledLayer removeFromSuperlayer];
    tiledLayer.delegate = nil;
}
// Set the CGPDFPageRef for the view.
- (void)setPage:(CGPDFPageRef)newPage
{
    CGPDFPageRelease(self->pdfPage);
    self->pdfPage = CGPDFPageRetain(newPage);

    //self->pdfPage = newPage;
}


-(void)drawRect:(CGRect)r
{
}


// Draw the CGPDFPageRef into the layer at the correct scale.
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{   

    // First fill the background with white.
    CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
    CGContextFillRect(context,self.bounds);

    CGContextSaveGState(context);
    // Flip the context so that the PDF page is rendered
    // right side up.
    CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // Scale the context so that the PDF page is rendered 
    // at the correct size for the zoom level.
    CGContextScaleCTM(context, myScale,myScale);    
    CGContextDrawPDFPage(context, pdfPage);
    CGContextRestoreGState(context);

}

// Clean up.
- (void)dealloc {
    CGPDFPageRelease(pdfPage);

    [super dealloc];
}

And this is where i try to stop and release PDF in view controller: v is instance of TiledPDFView

 -(void) stopDwaring {
     [v stopDrawing];
     [v removeFromSuperview];
     [v release];
     [self.view removeFromSuperview];
     self.view = nil;
     CGPDFDocumentRelease(pdf);

 }
like image 966
negersiu Avatar asked Oct 06 '10 10:10

negersiu


3 Answers

this post helped me solving my own trouble with CATiledLayer. I used TiledPDFview.m from Apple's documentation as example. Since I need to redraw the entire view and all tiles at some point, I use a CATiledLayer as property. When exiting and deallocating the viewcontroller, it crashed with [CATiledLayer retain]: Message sent to deallocated instance. Here is my dealloc method of the view controller:

- (void)dealloc {
    self.tiledLayer.contents=nil;
    self.tiledLayer.delegate=nil;
    [self.tiledLayer removeFromSuperlayer];

    // note: releasing the layer still crashes- 
    // I guess removeFromSuperlayer releases it already, 
    // but couldn't find documentation so far.
    // So that's why it's commented out:
    // [self.tiledLayer release], self.tiledLayer=nil;

    //release the other viewcontroller stuff... 
    [super dealloc];
}

That works for me. Hope it helps someone.

like image 105
marimba Avatar answered Nov 15 '22 01:11

marimba


Remove the CATiledLayer from its superlayer before releasing the CGPDFDocumentRef.

[yourTiledLayer removeFromSuperlayer];

Dont forget to set it's delegate to nil too.

yourTiledLayer.delegate = nil;

After that, you can safely release your CGPDFDocumentRef.

Edit after OP adds code:

Did you get pdfPage using CGPDFDocumentGetPage()? If so, you shouldn't release it, it is an autoreleased object.

Regarding how to add it as sublayer: You don't actually need TiledPDFView. In your view controller, you can simply do this:

CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.delegate = self; //sets where tiledLayer will look for drawLayer:inContext:
tiledLayer.tileSize = CGSizeMake(512.0f, 512.0f);
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 4;
tiledLayer.frame = CGRectIntegral(CGRectMake(0.0f, 0.0f, 512.0f, 512.0f));
[self.view.layer addSublayer:tiledLayer];

Then move your drawLayer:inContext: implementation to your view controller.

Then in your view controller's dealloc, release it as:

[tiledLayer removeFromSuperlayer];
tiledLayer.delegate = nil;
CGPDFDocumentRelease(pdf);

Note that you can't do this on a UIView subclass, as the drawLayer:inContext: will conflict with the UIView's main layer.

like image 31
Altealice Avatar answered Nov 15 '22 00:11

Altealice


object.layer.contents = Nil

This should wait for the thread to finish. It helped in my case.

like image 33
krzyspmac Avatar answered Nov 15 '22 02:11

krzyspmac