ios - iOS - 将 PDF 转换为图像时过度使用内存导致崩溃
问题描述
这就是我想要实现的目标:用户在 UIDocumentPickerViewController 中选择一些 PDF 文档后,将文档的每一页转换为 UIImage,将该 UIImage 保存到磁盘并将其文件 url 存储在一个imageUrls
数组中。转换完所有文档后,我会将imageUrls
数组传递给我的下一个 ViewController。
以下代码可以正常工作,但会导致内存 (RAM) 的使用量急剧增加:我的应用程序在转换之前使用 92MB 内存,而当我尝试转换仅 25MB 的 PDF 文档时,它最多可以使用550MB 。虽然这在我的模拟器中运行,但它导致我用户的 iPhone XR 发生一些崩溃。我猜原因是过度使用内存。
以下是我进行转换的代码,如果有人可以帮助我确定问题所在,将不胜感激。
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
print("Import result: \(urls)"). // urls look like this [file:///Users/me/Library/Developer/CoreSimulator/Devices/.../my-document.pdf]
let group = DispatchGroup() // use group to monitor the completion of converting all picked PDF documents
var imageUrls = [URL]() // the URL array to pass to the next ViewController
for (docIndex, url) in urls.enumerated() {
group.enter()
// do conversion on global queue so UI is not blocked
DispatchQueue.global(qos: .userInitiated).async {
guard let pdfDocument = createPDFdocumentFromUrl(url) else { return } // helper method 1: createPDFdocumentFromUrl(_:URL)
SVProgressHUD.show(withStatus: "Converting PDF \(docIndex + 1)") // show a spinner
for page in (1...pdfDocument.numberOfPages) {
guard let image = pdfDocument.drawPage(page), // helper method 2: CGPDFDocument.drawPage(_:Int)
let imageUrl = image.saveToDisk(fileName: "drawing-\(docIndex)-\(page).jpg") // helper method 3: UIImage.saveToDisk(fileName: String)
else { continue }
imageUrls.append(imageUrl)
}
group.leave()
}
}
group.notify(queue: .main) {
SVProgressHUD.dismiss() // dismiss spinner
print("Pass imageUrls array to next ViewController")
}
}
这是我在上面的代码中使用的 3 个辅助方法:
// helper method 1
func createPDFdocumentFromUrl(_ url: URL) -> CGPDFDocument? {
CGPDFDocument(url as CFURL) ?? nil
}
extension CGPDFDocument {
// helper method 2: convert the specified PDF page into UIImage
func drawPage(_ page: Int) -> UIImage? {
guard let page = self.page(at: page) else { return nil }
let pageRect = page.getBoxRect(.mediaBox)
let renderer = UIGraphicsImageRenderer(size: pageRect.size)
let img = renderer.image { ctx in
UIColor.white.set()
ctx.fill(pageRect)
ctx.cgContext.translateBy(x: 0.0, y: pageRect.size.height)
ctx.cgContext.scaleBy(x: 1.0, y: -1.0)
ctx.cgContext.drawPDFPage(page)
}
return img
}
}
extension UIImage {
/// helper method 3: save image in `/www` folder
func saveToDisk(fileName: String) -> URL? {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil }
let wwwFolderUrl = documentsDirectory.appendingPathComponent("www")
let fileURL = wwwFolderUrl.appendingPathComponent(fileName)
guard let data = self.jpegData(compressionQuality: 1) else { return nil }
//Checks if file exists, removes it if so.
if FileManager.default.fileExists(atPath: fileURL.path) {
do {
try FileManager.default.removeItem(atPath: fileURL.path)
print("Removed old image")
} catch let removeError {
print("couldn't remove file at path", removeError)
return nil
}
}
do {
try data.write(to: fileURL)
} catch let error {
print("error saving file with error", error)
return nil
}
return fileURL
}
}