1

I am implementing a pdf reader.The way i am writing code is sufficient for many pdf's suddenly one single pdf came into picture with 300MB(total 1000 pages).The pdf is working fine up to 70 pages later it is killing my application i am checking in the divice(IPad1,V5.0) and simulator(V 5.0).In simulator i can navigate with all pages from starts at 1 till the last page but coming to device i cant do that.I seen memory allocation in the "Instruments tool" Image

On the image rectangle box showing me memory allocation and fluctuating of the memory utilization,for each single page newly rendered(first time after opening the app) CGContextDrawPDFPage method increasing 2MB of memory.I dont know why CGContextDrawPDFPage increasing drastically.I seen many blogs on this but there is no use and waste of time.Below is my sample code

otherPageRef = CGPDFDocumentGetPage(myDocumentRef, c);

            cropBox = CGPDFPageGetBoxRect(otherPageRef, kCGPDFCropBox);
            CGContextSaveGState(ctx);
            CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
            CGContextFillRect(ctx,CGContextGetClipBoundingBox(ctx));
            CGFloat aspectRatio=aspectFitSize.width/aspectFitSize.height;
            CGRect targetRect = layer.bounds;
            CGFloat xScale = targetRect.size.width / cropBox.size.width;
            CGFloat yScale = (targetRect.size.height-__TOP_BRANDING_BAR_HEIGHT) / cropBox.size.height;
            CGFloat scaleToApply = (xScale < yScale) ? xScale : yScale;
            CGContextTranslateCTM(ctx, -cropBox.origin.x, layer.bounds.size.height- __TOP_BRANDING_BAR_HEIGHT +cropBox.origin.y);
            CGContextScaleCTM(ctx, 1.0, -1.0);
            CGContextConcatCTM(ctx, CGAffineTransformMakeScale(scaleToApply, scaleToApply));
            if (scaleToApply == yScale){
                CGContextConcatCTM(ctx, CGAffineTransformMakeTranslation((layer.bounds.size.width-(cropBox.size.width*scaleToApply)-cropBox.origin.x)/(scaleToApply * 2.0), 0));
            }
            else{
                if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
                    CGContextConcatCTM(ctx, CGAffineTransformMakeTranslation(0, (layer.bounds.size.height- __TOP_BRANDING_BAR_HEIGHT -(cropBox.size.height*scaleToApply))/(scaleToApply*2.0)));
                }
                else {
                    CGContextConcatCTM(ctx, CGAffineTransformMakeTranslation(0, (layer.bounds.size.height- __TOP_BRANDING_BAR_HEIGHT -(cropBox.size.height*scaleToApply))/(scaleToApply*2.0)));
                }
            }


            CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); 
            CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);
            CGContextDrawPDFPage(ctx, otherPageRef);
            CGContextRestoreGState(ctx);

can any one guess what is the cause for my app crashing and please suggest me to handling technique.I even tried my cgpdfdocumentRef releasing and retaining method but no use.Your suggestion is more useful for me.Thanks in advance.

ajay
  • 3,245
  • 4
  • 31
  • 59

1 Answers1

1

Basically, your app uses too much memory and gets killed by the OS. Simulator has plenty of memory but iPad doesn't. This is why there is a difference in behavior between device and simulator.

The reason of large amount of memory being used is a bug/feature of the Quartz 2D. When a page is drawn, all objects used by the page are read into memory and are decompressed. And these decompressed objects are cached (wise decision) by the Quartz 2D. The problem is: these objects won't be removed from the cache until the PDF is closed.

So, the obvious way to go is:

  1. Open a PDF
  2. Draw 1-5 pages
  3. Close the PDF
  4. Repeat if needed

I used this approach and it works fine even for big PDFs with lots of images (magazines).

For more information you might want to have a look at Fast and Lean PDF Viewer for iPhone / iPad / iOs - tips and hints? discussion.

Community
  • 1
  • 1
Bobrovsky
  • 13,789
  • 19
  • 80
  • 130
  • +1 Thanks for your awesome hint i too follow your tips and let me check how it is working. – ajay Feb 09 '12 at 04:28
  • after following above steps my instruments memory fluctuating up to 25MB will it cause any crash issue. – ajay Feb 09 '12 at 06:08
  • I do not have exact numbers and "it depends", but I think that it safe to use 30-50 MB in your app. btw, you can handle memory warnings in your code (I've done that in mine). Whenever a memory warning is issued by the OS just close and reopen the PDF. – Bobrovsky Feb 09 '12 at 06:19
  • I tried to use below code to refresh document but it takes little time to update any guess to reduce the time pdfPagesRendered=0; NSLog(@"before =%@",[NSDate date]); NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init]; isMemoryWaringOccured=YES; CGPDFDocumentRelease(myDocumentRef); pdfUrl=[[NSURL alloc] initFileURLWithPath:[self.kbDataSource pdfPath]]; myDocumentRef= CGPDFDocumentCreateWithURL(pdfUrl); [pdfUrl release]; [pool release]; NSLog(@"after =%@",[NSDate date]); – ajay Feb 09 '12 at 08:53
  • I am not sure why you use `NSAutoreleasePool` in this code. Probably it's not needed. Other than this I have no ideas how to make opening of the PDF faster. – Bobrovsky Feb 09 '12 at 09:35