Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

ios - 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);
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...