You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 13:57:33