Swift中用PDFKit将UIImage数组转PDFDocument时内存溢出崩溃求助
解决UIImage数组转PDFDocument内存耗尽崩溃的问题
核心问题分析
直接用PDFPage(image: image)创建页面时,UIImage会以解压后的位图形式驻留内存,若数组包含大量高分辨率图像(比如相机原图),内存会快速累积导致崩溃。以下是针对性优化方案:
方案1:先压缩/调整图像尺寸
将图像缩放到与PDF页面匹配的合理尺寸(例如A4纸对应的72dpi分辨率:595×842像素),大幅降低单张图像的内存占用:
import UIKit import PDFKit extension UIImage { func scaledToPDFPageSize() -> UIImage? { // 适配A4纸的72dpi尺寸 let targetSize = CGSize(width: 595, height: 842) UIGraphicsBeginImageContextWithOptions(targetSize, false, 1.0) defer { UIGraphicsEndImageContext() } self.draw(in: CGRect(origin: .zero, size: targetSize)) return UIGraphicsGetImageFromCurrentImageContext() } } extension Array where Element: UIImage { func makePDF() -> PDFDocument? { let pdfDocument = PDFDocument() for (index, image) in self.enumerated() { guard let scaledImage = image.scaledToPDFPageSize(), let pdfPage = PDFPage(image: scaledImage) else { continue } pdfDocument.insert(pdfPage, at: index) } return pdfDocument } }
方案2:循环内用autoreleasepool管控临时对象
将单次图像处理逻辑包裹在autoreleasepool中,确保循环内的临时对象及时释放,避免内存堆积:
extension Array where Element: UIImage { func makePDF() -> PDFDocument? { let pdfDocument = PDFDocument() for (index, image) in self.enumerated() { autoreleasepool { guard let pdfPage = PDFPage(image: image) else { continue } pdfDocument.insert(pdfPage, at: index) } } return pdfDocument } }
方案3:从图像Data创建PDFPage(避免解压开销)
UIImage存储的是解压后的位图,内存占用远大于原始压缩数据(JPEG/PNG),直接用图像Data创建PDFPage能大幅减少内存消耗:
extension Array where Element: UIImage { func makePDF() -> PDFDocument? { let pdfDocument = PDFDocument() for (index, image) in self.enumerated() { autoreleasepool { guard let imageData = image.jpegData(compressionQuality: 0.8), let pdfPage = PDFPage(data: imageData) else { continue } pdfDocument.insert(pdfPage, at: index) } } return pdfDocument } }
方案4:组合优化(推荐)
把图像缩放、Data创建、autoreleasepool三者结合,最大化降低内存占用:
extension UIImage { func scaledToPDFPageSize() -> UIImage? { let targetSize = CGSize(width: 595, height: 842) UIGraphicsBeginImageContextWithOptions(targetSize, false, 1.0) defer { UIGraphicsEndImageContext() } self.draw(in: CGRect(origin: .zero, size: targetSize)) return UIGraphicsGetImageFromCurrentImageContext() } } extension Array where Element: UIImage { func makePDF() -> PDFDocument? { let pdfDocument = PDFDocument() for (index, image) in self.enumerated() { autoreleasepool { guard let scaledImage = image.scaledToPDFPageSize(), let imageData = scaledImage.jpegData(compressionQuality: 0.8), let pdfPage = PDFPage(data: imageData) else { continue } pdfDocument.insert(pdfPage, at: index) } } return pdfDocument } }
内容的提问来源于stack exchange,提问作者Aleksandr Ponomarev
相关产品推荐
相关产品推荐

