2013-02-05 17 views
5

बनाते समय मेमोरी चेतावनी और दुर्घटना जब एक बड़ा पीडीएफ जेनरेट करते हैं, तो मेरा ऐप एक स्मृति को एक चेतावनी प्राप्त करता है, फिर पीडीएफ की पीढ़ी की प्रक्रिया के दौरान दुर्घटनाग्रस्त हो जाता है। पीडीएफ एक वेब दृश्य, जब पृष्ठों एक निश्चित राशि से ऊपर मिलता है (डिवाइस पर निर्भर करता है) मैं स्मृति से बाहर चलाने में तैयारपीडीएफ

इस मामले में मेरे शोध अब तक मुझे सुराग समझने के लिए मैं करने की जरूरत है:

IGraphicsBeginPDFContextToFile

  1. को UIGraphicsBeginPDFContextToData बदलने के लिए एक अस्थायी फ़ाइल के लिए एक उचित पथ बनाएँ,

  2. कार्य करने के लिए है कि दो,

  3. +०१२३५१६४१०६
  4. फ़ाइल को लोड करने के लिए वेबव्यू पर दें।

  5. पूर्ण होने पर फ़ाइल हटाएं।

समस्या है, जबकि मुझे लगता है कि मैं इसे समझ (बस) pricipal में, मुझे पता है इस को प्राप्त करने के बारे में जाने के लिए कैसे नहीं है, या पूरी तरह से यह समझ इतनी के रूप में यह मेरे कोड के भीतर impliment करने के लिए। इस मामले में बहुत ज्यादा खुला appricated

इम किसी अन्य विचारों के लिए भी सलाह स्मृति दुर्घटना को रोकने के लिए

@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]; 
    } 
} 
} 

डिबग सांत्वना चेतावनी इनमें से एक लोड कर रहे हैं, तो दुर्घटना

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 
+0

भी crashlog शामिल –

+0

मैं माफी चाहता हूँ, लेकिन मुझे लगता है कि मैं कुछ याद किया:

कोड यह रहा। आप पीडीएफ फाइल जेनरेट करना चाहते हैं? आपका स्रोत क्या है? कुछ ग्राफिक्स संदर्भ? और आपके पास स्मृति समस्या कहां है? फ़ाइल उत्पन्न करते समय या इसे वेबव्यू में दिखाते समय? –

उत्तर

5

एक लंबे समय पहले एक पूरी तरह से अलग मंच पर मैं पीडीएफ फाइलें उत्पन्न कर रहा था और इस तरह की समस्या में चल रहा था। एक समय में एक ही पृष्ठ उत्पन्न करने का समाधान (इमेजिंग के लिए अगला खोलने से पहले प्रत्येक पृष्ठ (दस्तावेज़ नहीं) को बंद करना)। इससे मेरे कई पेज दस्तावेज़ों के लिए एक बड़ा अंतर आया। अपना कोड देखकर, यह वही समस्या है जिसका आप सामना कर रहे हैं। असल में, आपके पास एक अतिरिक्त मुद्दा है जो कि आप ग्राफिक्स में सभी पेज डेटा को ग्राफिकल रूप से पहले बना रहे हैं और फिर सभी पीडीएफ पृष्ठों को मेमोरी में भी बनाते हैं और यह दुर्घटनाग्रस्त हो जाता है। समस्या को ठीक करने के तरीके के विवरण के लिए नीचे पढ़ें।

पढ़ना here

ऐसा लगता है कि अनुक्रम आप चाहते है:

// 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(); 

तो यह क्या करना चाहिए एक समय में एक पृष्ठ के लिए स्मृति में प्रदान की गई डेटा की मात्रा रखना है (प्लस कुछ भूमि के ऊपर दस्तावेज वैश्विक डेटा के लिए)।

ठीक है। मैंने आपके कोड को देखा और ऐसा लगता है कि आप स्मृति में प्रस्तुत पृष्ठ की कम से कम 2 प्रतियों के साथ समाप्त हो रहे हैं, अगर मैं इसे सही ढंग से समझ रहा हूं।

यहां कुंजी है - केवल एक ही समय में एक पृष्ठ खींचें। आप यह नहीं दिखाते कि ICPDFEICRPage1 और ऐसे हैं, लेकिन ऐसा लगता है कि वे ऐसी वस्तुएं हैं जो पृष्ठ सामग्री को किसी प्रकार के UIView में प्रस्तुत कर रही हैं? इसका मतलब है कि उनके पास एक संपूर्ण दृश्य के लिए पिक्सेल डेटा है (यह प्रतिलिपि 1 है)। तो आप किसी भी पेज के लिए स्मृति का उपयोग कर रहे हैं, आप किसी भी पीडीएफ पेजों को प्रस्तुत करने से पहले एक बार में सभी को आकर्षित करेंगे। फिर आप पीडीएफ पेज संदर्भ खोलते हैं जो इसे NSMutableData (यह डेटा की दूसरी प्रति है) में प्रस्तुत करता है।

दूसरा मुद्दा यह है कि: आप उस पृष्ठ को प्रिंट करते समय प्रत्येक पृष्ठ के लिए केवल पीडीएफ पृष्ठ ग्राफिक्स संदर्भ में प्रस्तुत करने के बजाय मेमोरी निर्माण (एक दृश्य) में कुछ प्रकार के प्रतिपादन क्यों कर रहे हैं? मैं अनुमान अनुमान लगाता हूं कि ऐसा इसलिए है क्योंकि आपके पास फ़ील्ड और एक xib फ़ाइल में परिभाषित सब कुछ के साथ एक UIView पदानुक्रम है ताकि आपको सभी लेआउट और तारों के चित्रण और मैन्युअल रूप से ऐसा करने की आवश्यकता न हो। सही बात?

हां, तो ऐसा करने के लिए बात अपने पृष्ठों सरणी होना एक सरणी ICPDFEICR... वस्तुओं की जिनमें से आप क्या आदेश आप उन्हें चाहते हैं, उसमें चाहते सूची किसी तरह का हो के लिए है, लेकिन अगर वास्तविक आवंटित खुद वस्तुओं नहीं। शायद प्रत्येक संभावित प्रकार के पेज, अवलोकन, वितरण बोर्ड, और ऐसे के लिए एक enum परिभाषित करें। फिर आपके पेज सरणी केवल पूर्णांक की एक सरणी है (उन क्रम में वे क्रम जिन्हें आप दस्तावेज़ में प्रदर्शित करना चाहते हैं)।

फिर वर्तमान पृष्ठ के लिए वास्तविक वस्तु आवंटित करें, इसे पृष्ठ पर चित्रित करें, और उसके बाद इसे अगले पृष्ठ पर करने से पहले इसे छोड़ दें।

इसके अलावा, मुझे लगता है (आशा है!) आप एआरसी का उपयोग कर रहे हैं क्योंकि अन्यथा आपके पास इस कोड (!!!) में बहुत सारी मेमोरी लीक हैं।

उम्मीद है कि आपको सही रास्ते पर शुरू करने के लिए पर्याप्त रूप से पर्याप्त होगा। ओह, फ़ाइल तकनीक के साथ आपको इसे एक फ़ाइल पथ देना होगा और फिर आप उस पथ को फ़ाइल के रूप में पास करेंगे: // url को प्रदर्शित करने के लिए वेबव्यू पर।

हालांकि अब मैं इसके बारे में सोचता हूं, आप पीडीएफ प्रदर्शित करने के लिए UIWebView का उपयोग क्यों कर रहे हैं? एक विकल्प के लिए Zooming PDF Viewer नमूना देखें जो पूरे पीडीएफ दस्तावेज को प्रदर्शित करने के लिए स्मृति में लोड करने की कोशिश नहीं करता है।

+0

मैंने इसे Google खोज पर देखा और यह सुनिश्चित नहीं किया कि मेरे कोड, किसी भी सुझाव के संबंध में इसका उपयोग कैसे किया जाए? – JSA986

+0

मैंने अपने उत्तर का विस्तार बहुत अधिक विशिष्ट जानकारी के साथ किया ताकि यदि आप इसे फिर से पढ़ लेंगे तो मुझे विश्वास है कि आपको यह आपके प्रश्न का उत्तर मिलेगा। – Dad

+0

बस बहुत विस्तृत उत्तर के लिए धन्यवाद कहना चाहता था, मैं अभी भी इस मुद्दे को ठीक करने की कोशिश कर रहा हूं, मैं आपको कई बार जवाब देने के बावजूद इसके चारों ओर अपना सिर नहीं ले सकता। हाँ मैं एआरसी का उपयोग कर रहा हूँ, धन्यवाद फिर से – JSA986

2

यह समस्याएं हल करने में आपकी सहायता कर सकता है। ध्यान दें कि कोड

  • एक फ़ाइल
  • सामग्री जोड़ने बनाने शामिल [वेब दृश्य

में देखने 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]; 
    } 
    

    हैप्पी कोडिंग :)

  • 0

    कोशिश चक्र

    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

    के लिए अपने में @autoreleasepool उपयोग करने के लिए और कुछ नहीं काम करता है अगर आप मेरा समाधान की कोशिश कर सकते। यह वेब व्यू के माध्यम से स्क्रॉल करता है और एक बार पीडीएफ में एक पेज जोड़ता है। मैं इस समस्या को किसी अन्य तरीके से हल नहीं कर सका। इस समाधान का पिछला भाग यह है कि यह टाइमर का उपयोग करता है, और पीडीएफ उत्पन्न होने पर आपको ऐप में स्क्रॉलिंग दिखाई देगी।

    ... 
        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; 
    }