【发布时间】:2021-08-18 00:03:47
【问题描述】:
当最初的开发人员离开组织时,我们从另一个团队获得了一个项目。我需要修复一个缺陷。我有一些类似下面的代码,其中UIGraphicsBeginPDFContextToData 发生在Global 队列上。但这会给出如下内存警告UIView 扩展的renderToImage 不会发生在main 线程上。
我想将 renderToImage 包裹在 DispatchQueue.main.async 中,但它会破坏 someFunction 中的 for 循环。我不能在主线程上使用.sync。谁能告诉我如何完成renderToImage 等待Global 队列?
原始代码:
DispatchQueue.global(qos: .userInitiated).async {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
zip(self.pdfPages, self.pageViews).forEach { (page, view) in
let image = view.renderToImage()
guard let imageData = image.jpegData(compressionQuality: 0.5),
let compressedImage = UIImage(data: imageData) else { return }
UIGraphicsBeginPDFPageWithInfo(CGRect(origin: CGPoint.zero, size: page.originSize), nil)
compressedImage.draw(in: CGRect(origin: CGPoint.zero, size: page.originSize))
DispatchQueue.main.async {
self.progressLabel.text = "Processing PDF... \(page.pageNumber) / \(pageNumbers)"
}
}
UIGraphicsEndPDFContext()
DispatchQueue.main.async {
self.progressIndicator.stopAnimating()
self.progressView.isHidden = true
completionBlock?(pdfData as Data)
}
}
extension UIView {
func renderToImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0)
guard let context = UIGraphicsGetCurrentContext() else { return UIImage() }
layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
应用@paulw11 回答后:
fileprivate func generatePDF(_ completionBlock: ((_ pdfData: Data) -> Void)?) {
let pageNumbers = pageViews.count
progressView.isHidden = false
progressIndicator.startAnimating()
progressLabel.text = "Processing PDF... \(0) / \(pageNumbers)"
let semaphore = DispatchSemaphore(value: 0)
let pdfContextQueue = DispatchQueue(label: kMessagesFaxPDFConversionQueue, target: DispatchQueue.global(qos: .userInitiated))
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
pdfContextQueue.async {
zip(self.pdfPages, self.pageViews).forEach { (page, view) in
view.renderToImage { image in
guard let imageData = image.jpegData(compressionQuality: 0.5),
let compressedImage = UIImage(data: imageData) else { return }
UIGraphicsBeginPDFPageWithInfo(CGRect(origin: CGPoint.zero, size: page.originSize), nil)
compressedImage.draw(in: CGRect(origin: CGPoint.zero, size: page.originSize))
DispatchQueue.main.async {
self.progressLabel.text = "Processing PDF... \(page.pageNumber) / \(pageNumbers)"
}
semaphore.signal()
}
semaphore.wait()
}
UIGraphicsEndPDFContext()
DispatchQueue.main.async {
self.progressIndicator.stopAnimating()
self.progressView.isHidden = true
completionBlock?(pdfData as Data)
}
}
}
extension UIView {
func renderToImage(completion: @escaping ((UIImage) -> Void)) {
DispatchQueue.main.async {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
guard let context = UIGraphicsGetCurrentContext() else {
completion(UIImage()); return
}
self.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
completion(image!)
}
}
}
【问题讨论】:
-
你不应该使用
NSMutableDataswift。只需使用Data。 -
@Paulw11: UIGraphicsBeginPDFContextToData 期望 NSMutableData
-
@paulw11:在主队列中使用
UIGraphicsGetCurrentContext并在全局队列中使用UIGraphicsEndPDFContext是否正确?这就是我没有 pdfData 的原因吗? -
它们是不同的上下文。一个是为渲染图像而创建的上下文,另一个是渲染 PDF 的上下文。当您没有生成PDF时,您到底是什么意思?数据的长度是0吗?它是非零但空白的内容吗?