Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CGContextDrawPDFPage memory Leak - App Crash

When I analyze my app with Instruments, I found out that data allocated by CGContextDrawPDFPage is not released immediately. App getting crash because of CGContextDrawPDFPage.

enter image description here

enter image description here

Hello here is my code for drawing pdf in CATiledlayer

      - (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)context
    {
    if (_PDFPageRef == nil) {
        return;
    }
    CGPDFPageRef drawPDFPageRef = NULL;
    CGPDFDocumentRef drawPDFDocRef = NULL;

    @synchronized(self) // Briefly block main thread
    {
        drawPDFDocRef = CGPDFDocumentRetain(_PDFDocRef);
        if( _PDFPageRef != (__bridge CGPDFPageRef)([NSNull null]) )
            drawPDFPageRef = CGPDFPageRetain(_PDFPageRef);
        else
            return;
    }

    //CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
    //CGContextFillRect(context, CGContextGetClipBoundingBox(context));

    if (drawPDFPageRef != NULL) // Render the page into the context
    {
        CGFloat boundsHeight = viewBounds.size.height;

        if (CGPDFPageGetRotationAngle(drawPDFPageRef) == 0)
        {
            CGFloat boundsWidth = viewBounds.size.width;

            CGRect cropBox = CGPDFPageGetBoxRect(drawPDFPageRef, kCGPDFCropBox);
            int pageRotation = CGPDFPageGetRotationAngle(drawPDFPageRef);

            CGSize pageVisibleSize = CGSizeMake(cropBox.size.width, cropBox.size.height);
            if ((pageRotation == 90) || (pageRotation == 270) ||(pageRotation == -90)) {
                pageVisibleSize = CGSizeMake(cropBox.size.height, cropBox.size.width);
            }

            float scaleX = boundsWidth / pageVisibleSize.width;
            float scaleY = boundsHeight / pageVisibleSize.height;
            float scale = scaleX < scaleY ? scaleX : scaleY;

            // Offset relative to top left corner of rectangle where the page will be displayed
            float offsetX = 0;
            float offsetY = 0;

            float rectangleAspectRatio = boundsWidth / boundsHeight;
            float pageAspectRatio = pageVisibleSize.width / pageVisibleSize.height;

            if (pageAspectRatio < rectangleAspectRatio) {
                // The page is narrower than the rectangle, we place it at center on the horizontal
                offsetX = (boundsWidth - pageVisibleSize.width * scale) / 2;
            }
            else {
                // The page is wider than the rectangle, we place it at center on the vertical
                offsetY = (boundsHeight - pageVisibleSize.height * scale) / 2;
            }

            CGPoint point = CGPointMake(offsetX, offsetY);

            //CGRect cropBox = CGPDFPageGetBoxRect(drawPDFPageRef, kCGPDFCropBox);
            int rotate = CGPDFPageGetRotationAngle(drawPDFPageRef);

            //CGContextSaveGState(context);

            // Setup the coordinate system.
            // Top left corner of the displayed page must be located at the point specified by the 'point' parameter.
            CGContextTranslateCTM(context, point.x, point.y);

            // Scale the page to desired zoom level.
            CGContextScaleCTM(context, scale , scale);

            // The coordinate system must be set to match the PDF coordinate system.
            switch (rotate) {
                case 0:
                    CGContextTranslateCTM(context, 0, cropBox.size.height);
                    CGContextScaleCTM(context, 1, -1);
                    break;
                case 90:
                    CGContextScaleCTM(context, 1, -1);
                    CGContextRotateCTM(context, -M_PI / 2);
                    break;
                case 180:
                case -180:
                    CGContextScaleCTM(context, 1, -1);
                    CGContextTranslateCTM(context, cropBox.size.width, 0);
                    CGContextRotateCTM(context, M_PI);
                    break;
                case 270:
                case -90:
                    CGContextTranslateCTM(context, cropBox.size.height, cropBox.size.width);
                    CGContextRotateCTM(context, M_PI / 2);
                    CGContextScaleCTM(context, -1, 1);
                    break;
            }

            // The CropBox defines the page visible area, clip everything outside it.
            CGRect clipRect = CGRectMake(0, 0, cropBox.size.width, cropBox.size.height);
            CGContextAddRect(context, clipRect);
            CGContextClip(context);

            CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
            CGContextFillRect(context, clipRect);

            CGContextTranslateCTM(context, -cropBox.origin.x, -cropBox.origin.y);

            CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
          //               CGContextSetInterpolationQuality(context, kCGInterpolationMedium);
            CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);

            if(context != nil && context != (__bridge CGContextRef)([NSNull null]))
            {
                CGContextDrawPDFPage(context, drawPDFPageRef);
                //CGContextRestoreGState(context);
            }


        }
        else // Use CGPDFPageGetDrawingTransform for pages with rotation (AKA kludge)
        {
            CGContextTranslateCTM(context, 0.0f, boundsHeight); CGContextScaleCTM(context, 1.0f, -1.0f);

            CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(drawPDFPageRef, kCGPDFCropBox, viewBounds, 0, true));
        }

            //CGContextDrawPDFPage(context, drawPDFPageRef);
    }

    CGPDFPageRelease(drawPDFPageRef); // Cleanup
    CGPDFDocumentRelease(drawPDFDocRef);
}
like image 515
Ravindhiran Avatar asked Oct 24 '17 05:10

Ravindhiran


1 Answers

This is by design. To allow faster re-draws, the CGPDFDocumentRef caches page resources.

The only way to empty this cache is to release and re-open the CGPDFDocumentRef.

like image 89
Bobrovsky Avatar answered Sep 17 '22 15:09

Bobrovsky