内存泄漏,在do-catch块中。 iOS,Swift
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存泄漏,在do-catch块中。 iOS,Swift相关的知识,希望对你有一定的参考价值。
我正在查看我的应用程序中使用视觉检测文本的内存泄漏。
我收到内存泄漏时,使用树指向此行:
try imageRequestHandler.perform([self.textDetectionRequest])
我不确定为什么,希望有人能帮忙解决这个问题。
完整代码如下。
private func performVisionRequest(image: CGImage, orientation: CGImagePropertyOrientation) {
DispatchQueue.global(qos: .userInitiated).async {
do {
var imageRequestHandler = VNImageRequestHandler(cgImage: image, orientation: orientation, options: [:])
try imageRequestHandler.perform([self.textDetectionRequest])
} catch let error as NSError {
print("Failed to perform vision request: (error)")
}
}
}
这是全班:
import UIKit
import Vision
var noText: Bool!
var imageNo: UIImage!
internal class Slicer {
private var image = UIImage()
private var sliceCompletion: ((_ slices: [UIImage]) -> Void) = { _ in }
private lazy var textDetectionRequest: VNDetectTextRectanglesRequest = {
return VNDetectTextRectanglesRequest(completionHandler: self.handleDetectedText)
}()
internal func slice(image: UIImage, completion: @escaping ((_: [UIImage]) -> Void)) {
self.image = image
self.sliceCompletion = completion
self.performVisionRequest(image: image.cgImage!, orientation: .up)
}
// MARK: - Vision
private func performVisionRequest(image: CGImage, orientation: CGImagePropertyOrientation) {
DispatchQueue.global(qos: .userInitiated).async {
do {
let imageRequestHandler = VNImageRequestHandler(cgImage: image, orientation: orientation, options: [:])
try imageRequestHandler.perform([self.textDetectionRequest])
} catch let error as NSError {
self.sliceCompletion([UIImage]())
print("Failed to perform vision request: (error)")
}
}
}
private func handleDetectedText(request: VNRequest?, error: Error?) {
if let err = error as NSError? {
print("Failed during detection: (err.localizedDescription)")
return
}
guard let results = request?.results as? [VNTextObservation], !results.isEmpty else {
noText = true
print("Tony no text found")
var slices = [imageNo]
self.sliceCompletion(slices as! [UIImage])
slices = []
return }
noText = false
self.sliceImage(text: results, onImageWithBounds: CGRect(x: 0, y: 0, width: self.image.cgImage!.width, height: self.image.cgImage!.height))
}
private func sliceImage(text: [VNTextObservation], onImageWithBounds bounds: CGRect) {
CATransaction.begin()
var slices = [UIImage]()
for wordObservation in text {
let wordBox = boundingBox(forRegionOfInterest: wordObservation.boundingBox, withinImageBounds: bounds)
if !wordBox.isNull {
guard let slice = self.image.cgImage?.cropping(to: wordBox) else { continue }
slices.append(UIImage(cgImage: slice))
}
}
self.sliceCompletion(slices)
CATransaction.commit()
}
private func boundingBox(forRegionOfInterest: CGRect, withinImageBounds bounds: CGRect) -> CGRect {
let imageWidth = bounds.width
let imageHeight = bounds.height
// Begin with input rect.
var rect = forRegionOfInterest
// Reposition origin.
rect.origin.x *= imageWidth
rect.origin.y = ((1 - rect.origin.y) * imageHeight) - (forRegionOfInterest.height * imageHeight)
// Rescale normalized coordinates. Tony adde + 30 to increase the size of rect
rect.size.width *= imageWidth + 30
rect.size.height *= imageHeight + 30
return rect
}
}
答案
其他人告诉你的是正确的。你有两个引用self
(Slicer)实例的闭包,你需要在两个闭包中打破保留周期。我认为这一行是一个巨大的错误:
private lazy var textDetectionRequest: VNDetectTextRectanglesRequest = {
return VNDetectTextRectanglesRequest(completionHandler: self.handleDetectedText)
}()
除了保留周期之外,你什么都得不到。删除那些行!相反,只需在需要时创建匿名函数。替换这个:
try imageRequestHandler.perform([self.textDetectionRequest])
有了这个:
try imageRequestHandler.perform(
[VNDetectTextRectanglesRequest(completionHandler:{ req, err in
self.handleDetectedText(request:req, error:err)
})]
)
如果仍然存在泄漏(我怀疑),则将其更改为
try imageRequestHandler.perform(
[VNDetectTextRectanglesRequest(completionHandler:{ [weak self] req, err in
self?.handleDetectedText(request:req, error:err)
})]
)
另一答案
我想会是这样的:
DispatchQueue.global(qos: .userInitiated).async { [weak self] _ in
do {
var imageRequestHandler = VNImageRequestHandler(cgImage: image, orientation: orientation, options: [:])
try imageRequestHandler.perform([self?.textDetectionRequest])
} catch let error as Error {
print("Failed to perform vision request: (error)")
}
}
另一答案
self.textDetectionRequest
是lazy var
,它捕获了handleDetectedText
,这是一个closure
因此你应该使用像[unowned self]
或[weak self]
这样的捕获列表来避免保留周期。
private lazy var textDetectionRequest: VNDetectTextRectanglesRequest = { [unowned self] in
return VNDetectTextRectanglesRequest(completionHandler: self.handleDetectedText)
}()
另外,你可以传递VNRequest
数组作为依赖在performVisionRequest
函数中简化代码
internal func slice(image: UIImage, completion: @escaping ((_: [UIImage]) -> Void)) {
self.image = image
self.sliceCompletion = completion
let requests = self.textDetectionRequest
self.performVisionRequest(image: image.cgImage!, orientation: .up, requests: [requests])
}
// MARK: - Vision
private func performVisionRequest(image: CGImage, orientation: CGImagePropertyOrientation, requests: [VNRequest]) {
DispatchQueue.global(qos: .userInitiated).async {
do {
let imageRequestHandler = VNImageRequestHandler(cgImage: image, orientation: orientation, options: [:])
try imageRequestHandler.perform(requests)
} catch let error as NSError {
self.sliceCompletion([UIImage]())
print("Failed to perform vision request: (error)")
}
}
}
另一答案
在你的capture list封口中使用textDetectionRequest
:
lazy var textDetectionRequest: VNDetectTextRectanglesRequest =
{ [weak self] in
return VNDetectTextRectanglesRequest(completionHandler: self?.handleDetectedText)
}()
以上是关于内存泄漏,在do-catch块中。 iOS,Swift的主要内容,如果未能解决你的问题,请参考以下文章