1

I need to use AVFoundation for an app I'm writing. Basically scanning a barcode, and sending that information back to another ViewController. This was pretty easy/straight forward with Swift and UIKit and I had this working.

Now, I launch the ViewController using a sheet (passing in the @State variable so I can dismiss the sheet later):

.sheet(isPresented: $isShowingCamera, content: {
    ScanItem(isPresented: self.$isShowingCamera)
})

ScanItem is a UIViewRepresentable Here are the functions in ScanItem:

func makeCoordinator() -> ScanItem.Coordinator {
    return Coordinator(self)
}

public typealias UIViewControllerType = ScanBarcodeViewController

func makeUIViewController(context: UIViewControllerRepresentableContext<ScanItem>) -> ScanBarcodeViewController {
    return ScanBarcodeViewController()
}

func updateViewController(_ uiViewController: ScanBarcodeViewController, context: UIViewControllerRepresentableContext<ScanItem>) {
}

Inside I have the required methods and its displaying another UIViewController I created that uses AVFoundation to display the camera, and look for the barcode. Where I believe I need to progress is making the Coordinator handle the AVCaptureMetaData. I have the Coordinator like below:

class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
    let parent: ScanItem
    init(_ parent: ScanItem) {
        self.parent = parent
    }

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    let metaDataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
    if metaDataObj.stringValue != nil {
        self.parent.$metadata = metadataObj.stringValue
        self.parent.$isPresented = false
    }
}

I think I'm on the right track here. This function gets called normally in the extension of the viewcontroller as AVCaptureMetadataOutputObjectsDelegate. I think I need to set the Coordinator as the delegate, call the function, set some bindable variable (@Bindable var metadata: String) and handle it in the SwiftUI view.

My current errors: ScanBarcodeViewController (my viewcontoller to load the camera) cannot be constructed because it has no accessible initializers Which goes along with class ScanBarcodeViewController has not initializers self.parent.$metaData = metaDataObj.stringValue -> cannot assign value of type String to type Binding -- fixed self.parent.$isPresented = false -> cannot assign value of type Bool to type Binding -- fixed

1 Answer 1

1

Instead of passing self in Coordinator (which is struct, so copied), ie

Coordinator(self)

use binding to your model directly, so you can modify it, ie like

func makeCoordinator() -> Coordinator {
    return Coordinator(data: $metadata)
}

and in Coordinator..

final class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
    var data: Binding<String>

...

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    let metaDataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
    if metaDataObj.stringValue != nil {
        ...
        data.wrappedValue = metadataObj.stringValue
        ...
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.