Search code examples
iosobjective-cios6

Memory issue with PDF Pages drawn to view iOS 6.1


I've got some memory issue on a simple iPad/iPhone app that should display a (large) PDF. Here is what I do.

I've got a scrollView with 5 subviews. Each subview displays a page of my PDF. One page is always displayed, 2 pages on each side are preloaded. If you scroll, a no-more-needed view is taken, the new PDF page to preload is rendered and the view is repositioned inside the scrollView.

Everything works really fine except that memory issue. If I profile memory leaks, the live bytes grow from 4MB to 40MB+. The overall bytes grow up to 600 MB+. I think the live bytes should not really grow, as I have the same 5 views at any time. Or am I reading the values incorrect?

ARC is used.

This is the code that renders the PDF pages.

-(void)drawRect:(CGRect)inRect{
    self.ctx = UIGraphicsGetCurrentContext();
    CGContextSaveGState(self.ctx);

    CGRect cropBox = CGPDFPageGetBoxRect(self.pdfPage, kCGPDFCropBox);
    CGRect targetRect = [self bounds];
    CGFloat xScale = targetRect.size.width / cropBox.size.width;
    CGFloat yScale = targetRect.size.height / cropBox.size.height;
    CGFloat scaleToApply = xScale < yScale ? xScale : yScale;
    CGFloat newWidth = cropBox.size.width * scaleToApply;
    CGFloat newHeight = cropBox.size.height * scaleToApply;
    CGFloat xOffset = (targetRect.size.width - newWidth) / 2;
    CGFloat yOffset = (targetRect.size.height - newHeight) / 2;

    CGContextTranslateCTM(self.ctx, xOffset, [self bounds].size.height - yOffset);
    CGContextScaleCTM(self.ctx, 1.0, -1.0);
    CGContextConcatCTM(self.ctx, CGAffineTransformMakeScale(scaleToApply, scaleToApply));
    CGContextSetInterpolationQuality(self.ctx, kCGInterpolationHigh);
    CGContextSetRenderingIntent(self.ctx, kCGRenderingIntentDefault);
    CGContextDrawPDFPage(self.ctx, self.pdfPage);

    CGContextRestoreGState(self.ctx);
}

And this is the method that makes the view rerender to a new PDF page, if the old is no more needed.

- (void)redrawPdfPage:(CGPDFPageRef)pPdfPage withPageNum:(int)pPageNum {
    self.pdfPage = pPdfPage;
    self.pageNum = pPageNum;
    CGRect r = [self frame];
    r.origin.x = r.size.width * (self.pageNum - 1);
    [self setFrame:r];
    [self setNeedsDisplay];
}

Any advice on this will be appreciated, as I'm trying to figure out how to free the memory of the old PDF pages for days...


Solution

  • With ARC you still have to put some effort into managing Foundation objects. You can release old page using CGPDFPageRelease. Or you can add appropriate attribute to your pdfPage property declaration, as described in this answer.