我正在创建一个应用程序,在一个周期结束时,生成一个QR码,然后创建一个PDF文件。在多次运行该应用程序(测试了近 5 天(后,该应用程序停止执行其其他必需的功能。我发现每次应用程序生成QR并制作PDF时,内存图在应用程序的连续循环中都会变得越来越高。调试内存图指示 3 个内存泄漏:一个在 viewDidAppear 事件,另一个在 createPDF 方法,第三个在生成 QrCode 方法。每次用户开始新周期时,我都会删除PDF文件。我不知道如何处理这些内存泄漏。有人可以帮忙吗?这是代码:
let html = ""
override func viewDidAppear(_ animated: Bool) {
createPDF()
return
}
func createPDF() {
html = "<div style='display: flex; justify-content: center;'></div>"
generateQrCode(arg: true, completion: { (success) -> Void in
print("QR Code Generated")
let image1 = captureView()
let imageData1 = image1.pngData() ?? nil
let base64String1 = imageData1?.base64EncodedString() ?? ""
if success {
self.html += "<html><body><div style='text-align: center'><p><br></p><p><b><img width='50%' height='20%' src='data:image/png;base64,(String(describing: base64String1))'/><p><br></p><p><b></b></p></div></body></html>"
weak var webView = WKWebView(frame: self.view.frame)
self.view.addSubview(webView!)
webView!.navigationDelegate = self
webView!.loadHTMLString(html, baseURL: nil)
webView!.isUserInteractionEnabled = false
} else {
print("false")
}
})
}
func generateQrCode(arg: Bool, completion: (Bool) -> ()){
let data = self.dataToQr.data(using: .ascii, allowLossyConversion: false)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(data, forKey: "inputMessage")
let img = UIImage(ciImage: (filter?.outputImage)!)
self.qrImageView.image = img
completion(true)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let render = UIPrintPageRenderer()
render.addPrintFormatter(webView.viewPrintFormatter(), startingAtPageAt: 0)
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
let printable = page.insetBy(dx: 0, dy: 0)
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)
for i in 1...render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
pdfData.write(toFile: "(documentsPath)/(UserDefaults.standard.string(forKey: "yourName")!)_(UserDefaults.standard.string(forKey: "gameName")!)_Kapper.pdf", atomically: true)
print("(documentsPath)/apper.pdf")
webView.removeFromSuperview()
}
从我所看到的代码来看,您的内存泄漏似乎是由您在此闭包中对self
的强引用引起的
completion: { (success) -> Void in
print("QR Code Generated")
let image1 = captureView()
let imageData1 = image1.pngData() ?? nil
let base64String1 = imageData1?.base64EncodedString() ?? ""
if success {
self.html += "<html><body><div style='text-align: center'><p><br></p><p><b><img width='50%' height='20%' src='data:image/png;base64,(String(describing: base64String1))'/><p><br></p><p><b></b></p></div></body></html>"
weak var webView = WKWebView(frame: self.view.frame)
self.view.addSubview(webView!)
webView!.navigationDelegate = self
webView!.loadHTMLString(html, baseURL: nil)
webView!.isUserInteractionEnabled = false
} else {
print("false")
}
}
以下是要执行的操作:
- 在控制器的 viewDidLoad 方法中创建 webView,而不是在闭包内创建,或者使其成为情节提要上的 IBOutlet。然后将闭包中的
self
引用设置为弱引用,如下所示。
generateQrCode(arg: true, completion: { [weak self] (success) -> Void in
print("QR Code Generated")
let image1 = captureView()
let imageData1 = image1.pngData() ?? nil
let base64String1 = imageData1?.base64EncodedString() ?? ""
if success {
self?.html += "<html><body><div style='text-align: center'><p><br></p><p><b><img width='50%' height='20%' src='data:image/png;base64,(String(describing: base64String1))'/><p><br></p><p><b></b></p></div></body></html>"
self?.webView.navigationDelegate = self
self?.webView.loadHTMLString(html, baseURL: nil)
self?.webView.isUserInteractionEnabled = false
} else {
print("false")
}
})
这应该有效。让我知道结果如何。
有关更多上下文,请查看以下链接:如何在带参数的 swift 块中正确处理弱自我
阻止 Swift 中的保留周期?
https://medium.com/@sergueivinnitskii/most-common-memory-leak-trap-in-swift-4565dbae5445
PS:我已经很多年没有回答StackOverflow的问题了。 :)