tags:

views:

164

answers:

1

The task: create an image from a PDF file as fast background preview for my PDF displayed with the CATiledLayer (slower, higher resolution). Problem: I get pretty fast an error warning on my iPad "Received memory warning. Level=1" and shortly after "Received memory warning. Level=2" .. then the app crashes.

- (void) drawSinglePage:(CALayer *)layer inContext:(CGContextRef)ctx {
    CGContextSaveGState(ctx);
    CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
    CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx));
    @synchronized(self) {

        // Draw PDF for HighRes
        CGPDFPageRef page = CGPDFDocumentGetPage(page1, 1);
        CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
        CGFloat scaleRatio = 960/pageRect.size.height;
        CGFloat yOffset = ((960-pageRect.size.height)/scaleRatio)+960;

        CGContextTranslateCTM(ctx, -(layer.bounds.size.width-pageRect.size.width)/2, yOffset);
        CGContextScaleCTM(ctx, scaleRatio, -scaleRatio);
        CGContextConcatCTM(ctx, CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, layer.bounds, 0, true));
        CGContextDrawPDFPage(ctx, page);

        // Draw Background-Image as fast preview (PROBLEM HERE!!)
        UIGraphicsBeginImageContext(layer.bounds.size);
        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
        CGRect prob = CGContextGetClipBoundingBox(context);
        CGContextFillRect(context, prob);

        CGContextSaveGState(context);
        CGContextSetInterpolationQuality(context, kCGInterpolationLow);
        CGContextTranslateCTM(context, -(layer.bounds.size.width-pageRect.size.width)/2, yOffset);
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, CGRectMake(0.0, 0.0, layer.bounds.size.width, layer.bounds.size.height), 0, true));
        CGContextDrawPDFPage(context, page);
        CGContextRestoreGState(context);
        UIImage *back = UIGraphicsGetImageFromCurrentImageContext();
        NSData *jpegDataFile = UIImageJPEGRepresentation(back, 0.2f);
        UIImage *smBack = [[UIImage alloc] initWithData:jpegDataFile];      
        UIGraphicsEndImageContext();

        // Now set the subview
        UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:smBack];
        backgroundImageView.frame = CGRectMake(0.0, 0.0, smBack.size.width, smBack.size.height);
        backgroundImageView.contentMode = UIViewContentModeTopLeft;
        backgroundImageView.opaque = YES;
        [self.view addSubview:backgroundImageView];
        [self.view sendSubviewToBack:backgroundImageView];
        [backgroundImageView release];

    }
    CGContextRestoreGState(ctx);
}

}

Note: if I don't set the background image view everything is ok - so pretty sure I have to release something, but I tried everything. At the moment I have no Idea. Note: the "CGPDFDocumentRelease(page1)" will be called in the - (void)dealloc function of this ViewController.

+2  A: 

I don't know how many times your drawSinglePage:inContext: method is being called, but it will create a new image view with the image in it every time while not keeping a reference to it. This means a second call will increase memory usage, while only one image is visible.

So if this method is called multiple times you should either reuse the image view (set imageView.image = nil), or remove the earlier created image view before creating a new one. This will release the image already in memory which might prevent a memory warning during drawing of the page.

Also keep in mind that drawing a pdf page can spike the memory usage over 20 mb each time. So depending on how much memory your application is using already this alone could cause the memory warning. Keep memory usage low and do not try to draw more than one page at the same time.

Joris Kluivers