我正在创建一个应用程序,该应用程序在一个周期的末尾会生成QR码,然后创建PDF文件。在多次运行该应用程序(经过近5天的测试)后,该应用程序停止执行其其他必需的功能。我发现,每次应用程序生成QR并生成PDF时,内存图在应用程序的连续周期中都会越来越大。调试内存图指示3个内存泄漏:一个在viewDidAppear事件上发生,另一个在createPDF方法上发生,第三次在generateQrCode方法上发生。每当用户开始新的周期时,我都会删除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()
}
答案 0 :(得分:2)
根据我对代码的了解,您的内存泄漏似乎是由您对此闭包中的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")
}
}
这是做什么:
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")
}
})
这应该有效。让我知道结果如何。
有关更多背景信息,请查看以下链接: How to Correctly handle Weak Self in Swift Blocks with Arguments
https://medium.com/@sergueivinnitskii/most-common-memory-leak-trap-in-swift-4565dbae5445
P.S:多年来我都没有回答StackOverflow问题。 :)