0

I have a SwiftUI project in which uses UIViewControllerRepresentable to access a DataScannerViewController. The HomeView displays the camera data scanner and it is the initial screen shown when the app launches. If I navigate to another view from the TabView, and then return to the HomeView, the data scanning stops. I believe this is because try? viewController.startScanning() does not fire. I am unsure how to fix this issue, and I am seeking advice.

struct CameraViewRepresentable: UIViewControllerRepresentable {
    @Binding var shouldStartScanning: Bool
    @Binding var scanResult: String
    @Binding var triggerWords: Set<String>
    @ObservedObject var triggers: TriggerOptions
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIViewController(context: Context) -> DataScannerViewController {
        let viewController = DataScannerViewController(
            recognizedDataTypes: [.text()],
            qualityLevel: .balanced,
            isHighFrameRateTrackingEnabled: true,
            isHighlightingEnabled: true
        )
        viewController.delegate = context.coordinator
        try? viewController.startScanning()
        return viewController
    }
    
    func recognizeTextHandler(request: VNRequest) {
        let maxCandidates = 1
        
        guard let results = request.results as? [VNRecognizedTextObservation] else {
            return
        }
        
        for result in results {
            guard let firstCandidate =  result.topCandidates(maxCandidates).first else {
                print("No Candidate Found")
                continue
            }
            print("Candidate Found : \(firstCandidate)")
        }
    }
    
    func updateUIViewController(_ viewController: DataScannerViewController, context: Context) {
        if shouldStartScanning {
            try? viewController.startScanning()
            Task {
                for await item in viewController.recognizedItems {
                    item.forEach { item in
                        switch item {
                        case .text(let scannedText):
                            triggers.triggerableCollection.forEach { trigger in
                                if scannedText.transcript.contains(trigger) {
                                    triggerWords.insert(trigger)
                                    print("Trigger Determined: \(trigger)")
                                }
                            }
                        default:
                            break
                        }
                    }
                }
            }
        } else {
            viewController.stopScanning()
            shouldStartScanning = false
            print("\(#file) - \(shouldStartScanning)")
        }
    }
    
    class Coordinator: NSObject, DataScannerViewControllerDelegate {
        var parent: CameraViewRepresentable
        init(_ parent: CameraViewRepresentable) {
            self.parent = parent
        }
        
        func dataScanner(_ dataScanner: DataScannerViewController, didAdd addedItems: [RecognizedItem], allItems: [RecognizedItem]) {
            allItems.forEach { item in
                switch item {
                case .text(let scannedText):
                    parent.scanResult = scannedText.transcript
                default:
                    break
                }
            }
        }
    }
}

I attempted the following...

  • Added breakpoints on each function to determine when the functions were firing.
  • Added a boolean check, which is set to true at .onAppear of the view.

I expect that when I navigate back to the HomeView that the scanning resumes.

hallux
  • 61
  • 1
  • 8

1 Answers1

0

The func makeUIViewController only runs once when the view is first initialised and it seems to store the view in something similar to State. ie. Once the view is built it won't run again. This is similar as to how @State is initialised only on the initial view init and not on future init.

The func updateUIViewController will be called every time the HomeView is updated and redrawn. You have a Binding/State shouldStartScanning which is checked in this function. If this were updated correctly in the HomeView onAppear this will call the updateFunction. Or add another bool binding that you can set in HomeView when appropriate to force the updateUIViewController function to be called and logic to run the try? viewController.startScanning()

Hongtron
  • 217
  • 6