@@ -120,23 +120,14 @@ struct QRScannerView: UIViewControllerRepresentable {
120120 context. coordinator. reportError ( " Camera scanning is currently unavailable. " )
121121 return UIViewController ( )
122122 }
123- let scanner = DataScannerViewController (
124- recognizedDataTypes: [ . barcode( symbologies: [ . qr] ) ] ,
125- isHighlightingEnabled: true )
126- scanner. delegate = context. coordinator
127- do {
128- try scanner. startScanning ( )
129- } catch {
130- context. coordinator. reportError ( " Could not start QR scanner. " )
131- }
132- return scanner
123+ return QRScannerContainerViewController ( coordinator: context. coordinator)
133124 }
134125
135126 func updateUIViewController( _: UIViewController , context _: Context ) { }
136127
137128 static func dismantleUIViewController( _ uiViewController: UIViewController , coordinator: Coordinator ) {
138- if let scanner = uiViewController as? DataScannerViewController {
139- scanner. stopScanning ( )
129+ if let scanner = uiViewController as? QRScannerContainerViewController {
130+ scanner. stopScannerCapture ( )
140131 }
141132 coordinator. parent. onDismiss ( )
142133 }
@@ -145,6 +136,68 @@ struct QRScannerView: UIViewControllerRepresentable {
145136 Coordinator ( parent: self )
146137 }
147138
139+ final class QRScannerContainerViewController : UIViewController {
140+ private let coordinator : Coordinator
141+ private let scanner : DataScannerViewController
142+ private var didStartScanning = false
143+
144+ init ( coordinator: Coordinator ) {
145+ self . coordinator = coordinator
146+ self . scanner = DataScannerViewController (
147+ recognizedDataTypes: [ . barcode( symbologies: [ . qr] ) ] ,
148+ isHighlightingEnabled: true )
149+ super. init ( nibName: nil , bundle: nil )
150+ self . scanner. delegate = coordinator
151+ }
152+
153+ @available ( * , unavailable)
154+ required init ? ( coder _: NSCoder ) {
155+ fatalError ( " init(coder:) has not been implemented " )
156+ }
157+
158+ override func viewDidLoad( ) {
159+ super. viewDidLoad ( )
160+ self . view. backgroundColor = . systemBackground
161+ self . addChild ( self . scanner)
162+ self . scanner. view. translatesAutoresizingMaskIntoConstraints = false
163+ self . view. addSubview ( self . scanner. view)
164+ NSLayoutConstraint . activate ( [
165+ self . scanner. view. leadingAnchor. constraint ( equalTo: self . view. leadingAnchor) ,
166+ self . scanner. view. trailingAnchor. constraint ( equalTo: self . view. trailingAnchor) ,
167+ self . scanner. view. topAnchor. constraint ( equalTo: self . view. topAnchor) ,
168+ self . scanner. view. bottomAnchor. constraint ( equalTo: self . view. bottomAnchor) ,
169+ ] )
170+ self . scanner. didMove ( toParent: self )
171+ }
172+
173+ override func viewDidAppear( _ animated: Bool ) {
174+ super. viewDidAppear ( animated)
175+ // VisionKit owns the camera session; start it only after UIKit has
176+ // presented the scanner so sheet teardown cannot race construction.
177+ self . startScanningIfNeeded ( )
178+ }
179+
180+ override func viewWillDisappear( _ animated: Bool ) {
181+ self . stopScannerCapture ( )
182+ super. viewWillDisappear ( animated)
183+ }
184+
185+ func stopScannerCapture( ) {
186+ self . scanner. stopScanning ( )
187+ self . didStartScanning = false
188+ }
189+
190+ private func startScanningIfNeeded( ) {
191+ guard !self . didStartScanning else { return }
192+ do {
193+ try self . scanner. startScanning ( )
194+ self . didStartScanning = true
195+ } catch {
196+ self . coordinator. reportError ( " Could not start QR scanner. " )
197+ }
198+ }
199+ }
200+
148201 final class Coordinator : NSObject , DataScannerViewControllerDelegate {
149202 let parent : QRScannerView
150203 private var handled = false
0 commit comments