gpt4 book ai didi

ios - 创建PDF时内存警告和崩溃

转载 作者:可可西里 更新时间:2023-11-01 04:31:02 26 4
gpt4 key购买 nike

当生成大型 PDF 时,我的应用收到一条内存警告,然后在 PDF 的生成过程中崩溃。 PDF 被绘制到 Web View 中,当页面超过一定数量(取决于设备)时,内存不足

到目前为止,我对此事的研究使我明白我需要:

UIGraphicsBeginPDFContextToData 更改为 IGraphicsBeginPDFContextToFile

  1. 创建一个合理的临时文件路径,

  2. 将其交给函数,

  3. 将文件交给 webview 加载。

  4. 完成后删除文件。

问题是,虽然我认为我(只是)基本掌握了它,但我不知道如何着手实现它,或者完全理解它以便在我的代码中实现它。在这件事上的建议非常适用

我也对任何其他阻止内存崩溃的想法持开放态度

@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

最佳答案

很久以前,我在一个完全不同的平台上生成 PDF 文件并遇到了此类问题。解决方案是一次生成一个页面(在打开下一页进行成像之前关闭每一页(不是文档))。这对我的多页文档产生了巨大的影响。查看您的代码,这与您在此处面临的问题相同。实际上,您还有一个额外的问题,即您首先以图形方式在内存中构建所有页面数据,然后在内存中构建所有 pdf 页面,然后它崩溃了。请阅读下文,了解有关如何解决该问题的详细信息。

阅读 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 的对象?这意味着他们拥有整个 View 的像素数据(即副本 1)。因此,在渲染任何 pdf 页面之前,您将一次性绘制的每一页都在使用内存。然后打开 PDF 页面上下文,将其呈现为 NSMutableData(这是数据的第二个副本)。

另一个问题是:为什么要渲染到某种内存构造( View ),而不是在打印页面时只渲染到每个页面的 pdf 页面图形上下文?我猜测这是因为您有一个包含字段的 UIView 层次结构以及在 xib 文件中定义的所有内容,这样您就不必手动进行所有布局和字符串绘制等操作。正确吗?

如果是这样,那么要做的就是让你的页面数组成为一个数组,它是你想要的 ICPDFEICR... 对象的某种列表,按照你想要的顺序排列,但不是实际分配的对象本身。也许为每种可能的页面类型、观察结果、分发板等定义一个枚举。然后你的页面数组只是一个整数数组(这些枚举按照你想要在文档中显示的顺序排列)。

然后只为当前页面分配实际对象,将其映射到页面,然后在执行下一页之前释放它。

此外,我假设(希望!)您正在使用 ARC,否则这段代码中会出现大量内存泄漏 (!!!)。

希望这足以让您走上正确的道路。哦,使用文件技术,你需要给它一个文件路径,然后你只需将该路径作为 file://url 传递给 webview 即可显示。

虽然现在我想起来了,为什么要使用 UIWebView 来显示 PDF?看Zooming PDF Viewer不尝试将整个 PDF 文档加载到内存中以显示它的替代示例。

关于ios - 创建PDF时内存警告和崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14699194/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com