I have a problem and I really don't know how to solve it. I'm developing an app which uses Vision/VisionKit and every time I push on the button to run the camera in order to take a picture and scan the text, it takes memory. So, every time I press the button for the camera, memory will always increase.
My app crashes when it reaches up 1 gb of memory (after 9, 10 scans more or less). This is the Xcode Alert:
The App "xxx" quit unexpectedly. Message from debugger: Terminated due to memory issue.
In addition, when I take the picture and the app scans the text of that pic, I pass the data (the text) to another ViewController by clicking on the button "CopyText", but it seems that it doesn't free the memory or dismiss the previous view.
It looks like VNDocumentCameraViewController
is always open in background (I think).
I have never encountered this problem, but now it is happening. Any suggestion?
P.s.: I was curious and I tried to use the native app "Note" on my iPhone. After 13-14 scans, the app crashed and it resprang my device. I'm going crazy. Is this normal, then?
This is my code. I am hopeless
import UIKit
import Vision
import VisionKit
class ScanText: UIViewController, VNDocumentCameraViewControllerDelegate {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var TextScan: UITextView!
@IBOutlet weak var buttonStartShape: UIButton!
@IBOutlet weak var infoScattaUnaFoto: UILabel!
@IBOutlet weak var copyButtonShape: UIButton!
@IBOutlet weak var thisIsAPreviewLabel: UILabel!
var textRecognitionRequest = VNRecognizeTextRequest(completionHandler: nil)
private let textRecognitionWorkQueue = DispatchQueue(label: "MyVisionScannerQueue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem)
var classView = ViewController()
var arrayText = String()
let notificationGenerator = UINotificationFeedbackGenerator()
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.layer.cornerRadius = 20
self.imageView.clipsToBounds = true
}
override func viewWillAppear(_ animated: Bool) {
thisIsAPreviewLabel.isHidden = true
TextScan.layer.cornerRadius = 15
TextScan.clipsToBounds = true
copyButtonShape.layer.cornerRadius = 25
copyButtonShape.clipsToBounds = true
buttonStartShape.layer.cornerRadius = 25
buttonStartShape.clipsToBounds = true
TextScan.isEditable = false
setupVision()
}
@IBAction func TakePicture(_ sender: Any) {
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self
self.imageView.layer.cornerRadius = 20
self.imageView.clipsToBounds = true
self.infoScattaUnaFoto.isHidden = true
present(scannerViewController, animated: true)
}
private func setupVision() {
textRecognitionRequest = VNRecognizeTextRequest { (request, error) in
guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
var detectedText = ""
for observation in observations {
guard let topCandidate = observation.topCandidates(2).first else { return }
print("text \(topCandidate.string) has confidence \(topCandidate.confidence)")
detectedText += topCandidate.string
detectedText += "\n"
}
DispatchQueue.main.async {
self.thisIsAPreviewLabel.isHidden = false
self.TextScan.isHidden = false
self.copyButtonShape.isHidden = false
self.buttonStartShape.setTitle("Retake", for: .normal)
self.TextScan.text += detectedText
self.TextScan.flashScrollIndicators()
}
}
textRecognitionRequest.recognitionLevel = .accurate
}
private func processImage(_ image: UIImage) {
imageView.image = image
recognizeTextInImage(image)
}
private func recognizeTextInImage(_ image: UIImage) {
guard let cgImage = image.cgImage else { return }
TextScan.text = ""
textRecognitionWorkQueue.async {
let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
do {
try requestHandler.perform([self.textRecognitionRequest])
} catch {
print(error)
}
}
}
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
/* guard scan.pageCount >= 1 else {
controller.dismiss(animated: true)
return
}*/
for i in 0 ..< scan.pageCount {
let img = scan.imageOfPage(at: i)
processImage(img)
}
let originalImage = scan.imageOfPage(at: 0)
print(originalImage)
//let newImage = compressedImage(originalImage)
controller.dismiss(animated: true, completion: nil)
}
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
print(error)
controller.dismiss(animated: true, completion: nil)
}
func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
controller.dismiss(animated: true, completion: nil)
}
func compressedImage(_ originalImage: UIImage) -> UIImage {
guard let imageData = originalImage.jpegData(compressionQuality: 1),
let reloadedImage = UIImage(data: imageData) else {
return originalImage
}
return reloadedImage
}
//MARK: By tapping on this button, I pass all the data.
@IBAction func CopyText(_ sender: Any) {
if TextScan.text.isEmpty {
hapticTapped()
let alertController = UIAlertController(title: "Error", message:
"It's impossible to copy. Your text view is empty", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default))
self.present(alertController, animated: true, completion: nil)
}else{
self.dismiss(animated:true, completion: nil)
let vc = (storyboard?.instantiateViewController(identifier: "SpeakDetail") as? ViewController)!
vc.textscannerized = TextScan.text
self.navigationController?.pushViewController(vc, animated: true)
}
}
func hapticTapped() {
notificationGenerator.notificationOccurred(.error)
}
}