Custom Class that conforms VNDocumentCameraViewController and VNDocumentCameraViewControllerDelegate

For a Flutter project I need to call a method channel in order to run platform specific code for iOS devices.

I would like to provide the VNDocumentCameraViewController of the VisionKit framework and in order to send the image path back to Flutter, I need to register a completion handler that runs after the VNDocumentCameraViewController is dismissed.


Therefore, I have a FlutterChannelManager that initializes the custom class DocumentCameraHandler which conforms to VNDocumentCameraViewController and VNDocumentCameraViewControllerDelegate and provides a handler for the result.


The VNDocumentCameraViewController is presented as expected and I can scan documents and everything but when the view controller is dismissed, the VNDocumentCameraViewControllerDelegate methods are somehow not called and my app throws the following error on the main thread:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x1f9400aa8)


These are the relevant classes in my project:


@available(iOS 13.0, *)

class FlutterChannelManager: NSObject {


unowned let flutterViewController: UIViewController


init(flutterViewController: UIViewController) {

self.flutterViewController = flutterViewController

}


func setup(){

let documentCamera = buildDocumentCamera()

self.flutterViewController.present(documentCamera, animated: true)

}


func buildDocumentCamera() -> UIViewController {

return DocumentCameraHandler { (image) in

self.flutterViewController.dismiss(animated: true, completion: nil)

if let image = image {

print("SUCCESS")

} else {

print("ERROR")

}

}

}

}


@available(iOS 13.0, *)

class DocumentCameraHandler: VNDocumentCameraViewController, UINavigationControllerDelegate, VNDocumentCameraViewControllerDelegate {


var handler: ((_ image: UIImage?) -> Void)?


convenience init(handler: @escaping (_ image: UIImage?) -> Void) {

self.init()

self.delegate = self

self.handler = handler

}


func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {

handler?(scan.imageOfPage(at: 0))

}


func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {

handler?(nil)

}


func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {

handler?(nil)

}

}

Replies

In your question you mention that DocumentCameraHandler conforms to VNDocumentCameraViewController and VNDocumentCameraViewControllerDelegate. However, VNDocumentCameraViewController is not a protocol, it's a class.
So essentially you ended up with DocumentCameraHandler that is a VNDocumentCameraViewController subclass and you set it as a delegate of itself. When your DocumentCameraHandler is dismissed, it's released from the memory, so there is no delegate to call the methods on.
What I would suggest is to create an instance of VNDocumentCameraViewController, which is a self-contained view controller and assign DocumentCameraHandler as a delegate. DocumentCameraHandler in this case should only conform to VNDocumentCameraViewControllerDelegate protocol and implement delegate methods.