Quartz PDF API 导致内存不足崩溃

发布于 2024-09-06 19:38:59 字数 2489 浏览 8 评论 0原文

我在使用 iOS 版 Quartz PDF API 时遇到崩溃问题。目前我正在使用 SDK 4.0 GM Seed 进行编译并在我的 3.2 iPad 上运行(我尝试使用 3.2 SDK 得到相同的结果)。

我使用的所有代码均基于标准 Apple Quartz 文档以及来自互联网上的各种来源。所以我无法想象我正在做一些完全不同或错误的事情。

该代码在模拟器(所有版本,它是通用应用程序)中完美运行,甚至在使用“模拟内存警告”功能时也是如此。我使用了 Leaks 工具,它没有发现任何泄漏。构建和分析也什么也没发现。我的库中没有留下任何崩溃或内存不足日志。

所有这些让我相信设备内存不足。这种情况发生在浏览了 50 个 pdf 页面后,大约 35% 的页面有某种类型的图像(有些是整页,有些是图标)。它不会在任何特定页面上崩溃。我正在加载的 pdf 大约有 75 页和 3.5MB。

我仔细研究了该网站和互联网上的类似问题,并应用了下面代码中的一些建议。我现在在每次翻页时都会发布 pdf 文档参考,并且不再保留/发布页面参考。我还简化了图像交换,从使用 CGImages 简化为仅使用 UIGraphicsGetImageFromCurrentImageContext 函数。我尝试了各种切换图像的实现,包括用新分配的临时实例完全替换 pdfImgView (使用 [[UIImageView alloc] iniWithImage:UIGraphicsGetImageFromCurrentImageContext()] ),使用 pdfImgView 的设置器和释放温度。所有变体都通过了泄漏和分析器测试,但仍然表现出相同的崩溃行为。

那么,在我完全放弃 PDF 之前,有什么我应该尝试的东西或者我缺少的东西吗?

在界面处理程序中调用以交换页面和首次加载时的视图控制器代码:

[self drawPage];

// ...animation code...simple CATransition animation...crashes with or without

// scrollView is a UIScrollView that is a subview of self.view
[scrollView.layer addAnimation:transition forKey:nil];
// pdfImgView is a UIImageView that is a subview of scrollView
pdfImgView.image = UIGraphicsGetImageFromCurrentImageContext();

drawPage 方法用于配置 PDF 页面并将其绘制到上下文:

[CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("BME_interior.pdf"), NULL, NULL);
pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL); // instance variable, not a property
CFRelease(pdfURL);
CGPDFPageRef page = CGPDFDocumentGetPage(pdfRef, currentPage);

CGRect box = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
// ...setting scale and imageHeight, both floats...

if (UIGraphicsBeginImageContextWithOptions != NULL) {
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.view.frame.size.width, imageHeight), NO, 0.0);
} else {
    UIGraphicsBeginImageContext(CGSizeMake(self.view.frame.size.width, imageHeight));
}
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(@"page is %d, context is %d, pdf doc is %d, pdf page is %d", currentPage, context, pdfRef, page); // all prints properly

// ...setting up scrollView for new page, using same instance...

CGContextTranslateCTM(context, (self.view.frame.size.width-(box.size.width*scale))/2.0f, imageHeight);
CGContextScaleCTM(context, scale, -1.0*scale);

CGContextSaveGState(context);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);

CGPDFDocumentRelease(pdfRef);
pdfRef = NULL;

I'm having crashing issues using the Quartz PDF API for iOS. At the moment I am compiling with the SDK 4.0 GM Seed and running on my 3.2 iPad (I have tried using the 3.2 SDK with identical results).

All the code I am using is based on the standard Apple Quartz documentation and from various sources around the internets. So I can't image I'm doing something drastically different or wrong.

The code runs perfectly in the Simulator (all versions, it's a Universal app) and even while using the "Simulate Memory Warning" function. I've used the Leaks tool and there are no leaks that it finds. Build and Analyze also finds nothing. No crash or low memory log is left in my Library.

All this leads me to believe the device is running out of memory. This happens after running through say 50 pdf pages, with about 35% having an image of some sort (some full page some icon). It does not crash on any particular page. The pdf I am loading is about 75 pages and 3.5MB.

I've perused similar issues on this site and around the internets, and have applied some of the advice in the code below. I now release the pdf document reference on every page turn and I no longer retain/release a page reference. I've also simplified the image swapping from using CGImages to just using the UIGraphicsGetImageFromCurrentImageContext function. I've tried various implementations for switching the images, including replacing the pdfImgView completely with a newly allocated temp instance (using [[UIImageView alloc] iniWithImage:UIGraphicsGetImageFromCurrentImageContext()]), using the setter for pdfImgView and releasing the temp. All of the variations pass the Leaks and Analyzer tests, but still exhibit the same crashing behavior.

So, before I move away from PDFs altogether, is there something I should try or something I am missing?

View controller code that is called in interface handlers to swap pages and on first load:

[self drawPage];

// ...animation code...simple CATransition animation...crashes with or without

// scrollView is a UIScrollView that is a subview of self.view
[scrollView.layer addAnimation:transition forKey:nil];
// pdfImgView is a UIImageView that is a subview of scrollView
pdfImgView.image = UIGraphicsGetImageFromCurrentImageContext();

drawPage method used to configure and draw PDF page to the context:

[CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("BME_interior.pdf"), NULL, NULL);
pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL); // instance variable, not a property
CFRelease(pdfURL);
CGPDFPageRef page = CGPDFDocumentGetPage(pdfRef, currentPage);

CGRect box = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
// ...setting scale and imageHeight, both floats...

if (UIGraphicsBeginImageContextWithOptions != NULL) {
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.view.frame.size.width, imageHeight), NO, 0.0);
} else {
    UIGraphicsBeginImageContext(CGSizeMake(self.view.frame.size.width, imageHeight));
}
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(@"page is %d, context is %d, pdf doc is %d, pdf page is %d", currentPage, context, pdfRef, page); // all prints properly

// ...setting up scrollView for new page, using same instance...

CGContextTranslateCTM(context, (self.view.frame.size.width-(box.size.width*scale))/2.0f, imageHeight);
CGContextScaleCTM(context, scale, -1.0*scale);

CGContextSaveGState(context);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);

CGPDFDocumentRelease(pdfRef);
pdfRef = NULL;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一绘本一梦想 2024-09-13 19:38:59

啊哈!我通过在开始新的图像上下文之前添加 UIGraphicsEndImageContext(); 修复了崩溃。我现在甚至没有收到内存警告......

Aha! I've fixed the crashes by adding a UIGraphicsEndImageContext(); before beginning a new image context. I don't even get memory warnings now...

吾性傲以野 2024-09-13 19:38:59

CGContextDrawPDFPage 之前调用

CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);

解决了我的类似问题。

归功于 Johann 的回答:
CGContextDrawPDFPage占用大量内存

Calling

CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);

before CGContextDrawPDFPage solved a similar problem of mine.

Credits goes to this answer of Johann:
CGContextDrawPDFPage taking up large amounts of memory

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文