Warning about crashes and crashes when creating a PDF file

When generating a large PDF file, my application receives a memory warning and then crashes during the process of creating the PDF file. The PDF file is embedded in the web view when the pages exceed a certain size (depending on the device). My memory runs out

My research on this issue still makes me understand what I need:

change UIGraphicsBeginPDFContextToDatatoIGraphicsBeginPDFContextToFile

  • Create a reasonable path to a temporary file,

  • Give it to the function

  • Give the file to your web browser to download.

  • Delete the file when done.

The problem is that, although I think I understand it (simply) in pricipal, I don’t know how to do this, or completely understand it in order to inject it into my code. Tips in this matter are very convenient.

Im also open to any other ideas to stop a memory failure

@interface ICPDFPreviewController ()
@property (nonatomic, strong) Certificate *certificate;
@property (nonatomic, strong) NSData *pdfData;
@property (nonatomic) BOOL viewHasUnloaded;
- (void)generatePdf;
- (void)pdfDone:(NSData *)data;
- (NSData *)createPdfWithPages:(NSArray *)pages;
@end

@implementation ICPDFPreviewController
@synthesize certificate=_certificate;
@synthesize scrollView=_scrollView;
@synthesize webView=_webView;
@synthesize pdfData=_pdfData;
@synthesize viewHasUnloaded=_viewHasUnloaded;



- (void)generatePdf
 {
 NSMutableArray *pagesArray = [NSMutableArray array];

 if ([self.certificate.certificateType.title isEqualToString:@"Minor Works"]) {
[pagesArray addObject:[[ICPDFMinorWorksPage1 alloc] initWithCertificate:self.certificate]];
 [pagesArray addObject:[[ICPDFMinorWorksPage2 alloc] initWithCertificate:self.certificate]];

 } else if ([self.certificate.certificateType.title isEqualToString:@"EIC"]) {
[pagesArray addObject:[[ICPDFEICPage1 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICPage2 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICPage3 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICPage4 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICPage5 alloc] initWithCertificate:self.certificate]];
[self addDistributionBoardsToPagesArray:pagesArray];
ICPDFEICPageFinal *pageFinal = [[ICPDFEICPageFinal alloc]        initWithCertificate:self.certificate];
 pageFinal.pageNumber.text = [NSString stringWithFormat:@"%d", pagesArray.count+1];
[pagesArray addObject:pageFinal];

} else if ([self.certificate.certificateType.title isEqualToString:@"Domestic EIC"]) {
[pagesArray addObject:[[ICPDFDomesticEICPage1 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFDomesticEICPage2 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFDomesticEICPage3 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFDomesticEICPage4 alloc] initWithCertificate:self.certificate]];
[self addDistributionBoardsToPagesArray:pagesArray];
[pagesArray addObject:[[ICPDFDomesticEICPageFinal alloc] initWithCertificate:self.certificate]];

} else if ([self.certificate.certificateType.title isEqualToString:@"EICR"]) {
[pagesArray addObject:[[ICPDFEICRPage1 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICRPage2 alloc] initWithCertificate:self.certificate]];
[self addObservationsToPagesArray:pagesArray];
[self addDistributionBoardsToPagesArray:pagesArray];
[pagesArray addObject:[[ICPDFEICRInspection alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICRInspectionPage1 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICRInspectionPage2 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICRInspectionPage3 alloc] initWithCertificate:self.certificate]];
[pagesArray addObject:[[ICPDFEICRPageFinal alloc] initWithCertificate:self.certificate]];
 }

// Set page count on all pages
int pageNumber = 0;
for (ICCertificateComponent *page in pagesArray) {
page.pageNumber.text = [NSString stringWithFormat:@"%d", ++pageNumber];
page.pageCount.text = [NSString stringWithFormat:@"%d", pagesArray.count];
}

 NSData *pdfData = [self createPdfWithPages:pagesArray];
[self performSelectorOnMainThread:@selector(pdfDone:) withObject:pdfData waitUntilDone:YES];

 }

- (void)pdfDone:(NSData *)data
 {
 self.pdfData = data;
[self.webView loadData:self.pdfData MIMEType:@"application/pdf" textEncodingName:@"utf-8"      baseURL:nil];
 [ICUtils removeProgressView];
 }

 - (NSData *)createPdfWithPages:(NSArray *)pages
  {
 // Creates a mutable data object for updating with binary data, like a byte array
 NSMutableData *pdfData = [NSMutableData data];

 ICCertificateComponent *firstPage = [pages objectAtIndex:0];

UIGraphicsBeginPDFContextToData(pdfData, firstPage.contentView.bounds, nil);

 for (int i = 0; i < pages.count; i++) {
 ICCertificateComponent *thisPage = [pages objectAtIndex:i];
 UIGraphicsBeginPDFPageWithInfo(thisPage.contentView.bounds, nil);


 CGContextRef pdfContext = UIGraphicsGetCurrentContext();
 [thisPage.contentView.layer renderInContext:pdfContext];
 }

 UIGraphicsEndPDFContext();

 return pdfData;
}

- (void)addDistributionBoardsToPagesArray:(NSMutableArray *)pagesArray
{
int pageCount = pagesArray.count;
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createdAt"       ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; 
NSArray *boards = [self.certificate.distributionBoards      sortedArrayUsingDescriptors:sortDescriptors];
 for (DistributionBoard *thisBoard in boards) {
DebugLog(@"Creating a board page");
ICPDFDistributionBoard *boardPage = [[ICPDFDistributionBoard alloc]        initWithDistributionBoard:thisBoard];
boardPage.pageNumber.text = [NSString stringWithFormat:@"%d", ++pageCount];
DebugLog(@"Page number is %d", pageCount);
[pagesArray addObject:boardPage];

NSSortDescriptor *circuitDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createdAt"     ascending:YES];
NSArray *circuitDescriptors = [[NSArray alloc] initWithObjects:circuitDescriptor, nil]; 
NSArray *circuits = [thisBoard.circuits sortedArrayUsingDescriptors:circuitDescriptors];

 //int circuitCount = circuits.count;
 ICPDFCircuitDetails *circuitDetails = boardPage.circuitDetails;

int circuitCount = 0;
for (Circuit *thisCircuit in circuits) {
circuitCount++;
if (circuitCount > 16) {
    // Add an extension page
    DebugLog(@"Adding an extension sheet");
    circuitCount = 1;
    ICPDFDistributionBoardExtension *boardExtension = [[ICPDFDistributionBoardExtension  alloc]   initWithDistributionBoard:thisBoard];
    [pagesArray addObject:boardExtension];
    boardExtension.pageNumber.text = [NSString stringWithFormat:@"%d", ++pageCount];
    circuitDetails = boardExtension.circuitDetails;
   }
    NSString *key = [NSString stringWithFormat:@"circuitRow%d", circuitCount];
   ICCircuitRow *circuitRow = [circuitDetails valueForKey:key];
   [circuitRow populateFromCircuit:thisCircuit];
  }
 }
}

debug console warnings - loading them and then crashing

 2013-02-08 10:38:35.475 iCertifi[5772:907] Received memory warning.
 2013-02-08 10:38:35.477 iCertifi[5772:907] <ICPDFPreviewController: 0x1eb28930>   didReceiveMemoryWarning
+5
source share
4 answers

- PDF . , ( ( ), ). . , , . , , , PDF , . , , .

, :

// start pdf document using default page size (CGRectZero)
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil); 

// then loop through your content drawing it one page at a time.
for ( page p in pages )   // or whatever you are cycling over for page content
{
   UIGraphicsBeginPDFPage();   // or UIGraphicsBeginPDFPageWithInfo

  // do your drawing to the page here by drawing to the current graphics context.
  // if you are setting up transforms and such

}
// close out the last page and the document both
UIGraphicsEndPDFContext();

, , ( ).

Ok. , , 2 , .

- . , ICPDFEICRPage1 , , , UIView - ? , ( 1). , , , PDF-. PDF, NSMutableData ( ).

: - () , pdf ? , , UIView , xib, . ?

, , - - ICPDFEICR..., , , , . , , , .. - ( , ).

, , .

, (!), ARC, (!!!).

, , , . , , ://url - .

, , UIWebView PDF? PDF Viewer , PDF , .

+5

, . ,

  • [ UIGraphicsGetCurrentContext();
  • -

- (IBAction)buttonPress:(id)sender
{
    [self createPDFData:[self getPDFFileName]];
}
-(NSString *)getPDFFileName
{
    NSString * fileName = @"Info.PDF";

    NSArray *arrayPaths =
    NSSearchPathForDirectoriesInDomains(
                                        NSDocumentDirectory,
                                        NSUserDomainMask,
                                        YES);
    NSString * path = [arrayPaths objectAtIndex:0];
    NSString *pdfFileName = [path stringByAppendingPathComponent:fileName];
    NSLog(@"path : %@",path);
    NSLog(@"pdf file name : %@",pdfFileName);
    return pdfFileName;

}

-(void)showPDFFile
{


    UIWebView *  webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,44,1024,748)];

    NSURL *url = [NSURL fileURLWithPath:[self getPDFFileName]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [webView setScalesPageToFit:YES];
    [webView loadRequest:request];

    [self.view addSubview:webView];

}


-(void)createPDFData:(NSString *)fileName{

    CGRect pageFrame = CGRectMake(0,0,768,1024);
    UIGraphicsBeginPDFContextToFile(fileName, CGRectZero, nil);//This starts drawing a pdf to file named "filename"  UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);//For each new page call this
    UIGraphicsGetCurrentContext();
    UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);//Next or new Page
    NSString * timeLabel = [NSString stringWithFormat:@"Some text"];
    [timeLabel drawInRect:CGRectMake(200, 200, 428, 44) withFont:[UIFont boldSystemFontOfSize:10] lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
    UIGraphicsEndPDFContext();
    [self showPDFFile];
}

:)

+2

@autoreleasepool

for (int i = 0; i < pages.count; i++) {

// notice this line 
     @autureleasepool 
     {
       ICCertificateComponent *thisPage = [pages objectAtIndex:i];
       UIGraphicsBeginPDFPageWithInfo(thisPage.contentView.bounds, nil);


       CGContextRef pdfContext = UIGraphicsGetCurrentContext();
       [thisPage.contentView.layer renderInContext:pdfContext];
     }
 }
0

If nothing works, you can try my solution. It scrolls through webView and adds one page at a time to the PDF. I could not solve this problem differently. The back of this solution is that it uses a timer, and you will see the scroll in the application while the PDF is being created.

Here is the code:

...
    CGPoint savedContentOffset;
    CGRect savedFrame;
    NSMutableData * pdfData;
    int pdfOffset;
    NSTimer *timer;
...

- (void)preparePdf {
    CGFloat height = aWebView.scrollView.contentSize.height;
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    int pageHeight = screenRect.size.height;

    savedContentOffset = aWebView.scrollView.contentOffset;
    savedFrame = aWebView.frame;
    pdfData=[NSMutableData data];

    aWebView.scrollView.contentOffset = CGPointZero;
    aWebView.frame = CGRectMake(aWebView.frame.origin.x,aWebView.frame.origin.y,aWebView.frame.size.width,pageHeight);

    UIGraphicsBeginPDFContextToData(pdfData, aWebView.frame, nil);

    NSLog(@"pageHeight = %d", pageHeight);
    pdfOffset = 0;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.4
                                             target: self
                                           selector: @selector(printPdfPage:)
                                           userInfo: nil
                                            repeats: YES];
}

- (void) printPdfPage: (NSTimer*) timer {
    CGFloat height = aWebView.scrollView.contentSize.height;
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    int pageHeight = screenRect.size.height;

    NSLog(@"pdfOffset = %d", pdfOffset);
    UIGraphicsBeginPDFPage();
    [aWebView drawViewHierarchyInRect:CGRectMake(0, 0, screenRect.size.width, pageHeight) afterScreenUpdates:YES];

    pdfOffset += pageHeight;
    aWebView.scrollView.contentOffset = CGPointMake(0, pdfOffset);

    if (pdfOffset > height) {
        [timer invalidate];
        NSLog(@"pdf data size: %ld", pdfData.length);
        [self emailPdf: pdfData];
    }
}

- (void) emailPdf: (NSMutableData*) pdfData {

    // finally end the PDF context.
    UIGraphicsEndPDFContext();

    aWebView.scrollView.contentOffset = savedContentOffset;
    aWebView.frame = savedFrame;

    MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
    mailer.mailComposeDelegate = self;
    [mailer setSubject:[@"iPad Screenshot " stringByAppendingString:[self getDate]]];
    [mailer addAttachmentData:pdfData mimeType:@"application/pdf" fileName:[[self getDate] stringByAppendingPathExtension:@"pdf"]];
    NSString *emailBody = @"";
    [mailer setMessageBody:emailBody isHTML:NO];
    [self presentViewController:mailer animated:YES completion:nil];

    if ([SVProgressHUD isVisible]) {
        [SVProgressHUD showSuccessWithStatus:@"Screenshot prepared."];
    }
    pdfData = nil;
    timer = nil;
}
0
source

All Articles