views:

126

answers:

2

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);

 }
+2  A: 

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.

Altealice
Still does not help. On my view (which uses CATiledLayer) i have a method-(void) stopDrawing { [tiledLayer removeFromSuperlayer]; tiledLayer.delegate = nil; } I call this method, then release CGPDFDocumentRef...
Maciulis
When do you call -stopDrawing? I assumed you were releasing the CGPDFDocumentRef in -dealloc. Also, is the CATiledLayer your view's main layer or just a sublayer? My solution is only tested with the CATiledLayer as a sublayer, not as the main layer. I recommend you just add the CATiledLayer as a sublayer, not as a replacement to the view's main layer.
Altealice
If that still doesn't help, do you mind adding more code to your post to help? Like where you init the CGPDFDocumentRef, where and how you add your CATiledLayer, your -drawLayer:inContext:, and where you release your CGPDFDocumentRef.
Altealice
CATiledLayer is main layer. I edited my post, provided some code. How to make CATiledLayer a sublayer that drawLayer:inContext method would be executed on that sublayer?
Maciulis
A: 

It looks like you're doing the same thing I am, which is borrowing the ZoomingPDFView code and integrating it into your project. If your UIScrollView delegate methods in PDFScrollView are unchanged, you can solve your problem by just commenting both lines of your dealloc method (in TiledPDFView). That stuff should only be happening when you kill the parent view, anyway.

Brandon