Я использую CodeScanner Пола Хадсона для сканирования штрих-кодов в моем приложении.
Я хочу, чтобы считыватель штрих-кода загружался, когда приложение открыто, а также имел оверлей.
Я хочу чтобы иметь возможность запускать сканер при запуске без нажатия кнопки. Я думал, что это будет так же просто, как просто иметь тело в ContentView:
CodeScannerView(codeTypes: [.qr], simulatedData: "Some simulated data", completion: self.handleScan)
Но это выдает:
Terminating app due to uncaught exception 'NSRangeException'
Что я не понимаю, так как переменные я Я передаю такие же, как у меня, кнопка не меняет никаких значений. Единственный массив в нем - [.qr], которому я даю значение.
Я начал изучать UIKit, но решил изучить SwiftUI, и мне было намного сложнее gr asp, поэтому я, вероятно, отсутствуют некоторые базовые c знания.
В моем ContentView:
struct ContentView: View {
var body: some View {
ZStack() {
ScannerView()
ScannerOverlayView()
}
}
}
ScannerView:
import SwiftUI
import CodeScanner
struct ScannerView: View {
@State private var isShowingScanner = false
var body: some View {
Button(action: {
self.isShowingScanner = true
}) {
Text("Show Scanner")
}
.sheet(isPresented: $isShowingScanner) {
CodeScannerView(codeTypes: [.qr], simulatedData: "Some simulated data", completion: self.handleScan)
}
}
private func handleScan(result: Result<String, CodeScannerView.ScanError>) {
self.isShowingScanner = false
switch result {
case .success(let data):
print("Success with \(data)")
case .failure(let error):
print("Scanning failed \(error)")
}
}
}
ScannerViewOverlay
Import SwiftUI
struct ScannerOverlayView: View {
var body: some View {
VStack() {
HStack() {
VStack() {
Spacer()
Image("bookmark-icon")
Text("Saved items")
}
Spacer()
VStack() {
Spacer()
Image("settings-icon")
Text("Settings")
}
}
.padding(.horizontal)
}
}
}
Вот начало CodeScanner:
import AVFoundation
import SwiftUI
public struct CodeScannerView: UIViewControllerRepresentable {
public enum ScanError: Error {
case badInput, badOutput
}
public class ScannerCoordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
var parent: CodeScannerView
var codeFound = false
init(parent: CodeScannerView) {
self.parent = parent
}
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if let metadataObject = metadataObjects.first {
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
guard let stringValue = readableObject.stringValue else { return }
guard codeFound == false else { return }
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
found(code: stringValue)
// make sure we only trigger scans once per use
codeFound = true
}
}
func found(code: String) {
parent.completion(.success(code))
}
func didFail(reason: ScanError) {
parent.completion(.failure(reason))
}
}