0

I am trying to make a barcode scanner app. As soon as the camera session begins, the app crashes within a few seconds. enter image description here

I am unable to find the reason behind this. and, how to fix this one.

I have used https://www.appcoda.com/barcode-reader-swift/ to make the barcde scanner.

import Foundation
import UIKit
import AVFoundation
import CoreData
enum BarcodeScanError : String{
    case cameraLoadFailed = "Camera Load Failed"
    case NoValidBarcode = "No Valid Barcode"
    
}

class ScanBoardingPassViewController : UIViewController {


//MARK: - Properties
var viewModel : ScanBoardingPassViewModel? = nil
var captureSession : AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
var qrCodeFrameView: UIView?


private let supportedCodeTypes = [AVMetadataObject.ObjectType.aztec,
                                 AVMetadataObject.ObjectType.pdf417]

//MARK: - Outlets
@IBOutlet weak var btnCancel: UIButton!

//MARK: - View Life Cycle
override func viewDidLoad() {
    viewModel = ScanBoardingPassViewModel()
    self.captureSession = AVCaptureSession()
    self.setUpView()
    super.viewDidLoad()
    
}

override func viewWillDisappear(_ animated: Bool) {

    super.viewWillDisappear(true)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//MARK: - Set Up View
func setUpView() {
            self.setUpBarCodeScanner()
    self.view.bringSubviewToFront(self.btnCancel)

            self.setUpBarcodeRecognizerFrame()
}

private func setUpBarCodeScanner() {
    // Get the back-facing camera for capturing videos
    guard let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) else {
        debugPrint(BarcodeScanError.cameraLoadFailed)
        return
    }
    
    do {
        // Get an instance of the AVCaptureDeviceInput class using the previous device object.
        let input = try AVCaptureDeviceInput(device: captureDevice)
        
        // Set the input device on the capture session.
        captureSession?.addInput(input)
        
        // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
        let captureMetadataOutput = AVCaptureMetadataOutput()
        captureSession?.addOutput(captureMetadataOutput)
        
        // Set delegate and use the default dispatch queue to execute the call back
        captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        captureMetadataOutput.metadataObjectTypes = supportedCodeTypes
        //            captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
        
    } catch {
        // If any error occurs, simply print it out and don't continue any more.
        print(error)
        return
    }
    
    // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
    videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
    videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    videoPreviewLayer?.frame = view.layer.bounds
    view.layer.addSublayer(videoPreviewLayer!)
    
    // Start video capture.
    captureSession?.startRunning()
}

private func setUpBarcodeRecognizerFrame() {
    // Initialize QR Code Frame to highlight the QR code
    qrCodeFrameView = UIView()
    
    if let qrCodeFrameView = qrCodeFrameView {
        qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
        qrCodeFrameView.layer.borderWidth = 2
        view.addSubview(qrCodeFrameView)
        view.bringSubviewToFront(qrCodeFrameView)
    }
}


//MARK: - Outlets
@IBAction func btnCancelPressed(_ sender: UIButton) {
    self.dismissView()
    
}

    func dismissView() {
        self.dismiss(animated: true, completion: nil)
    }
    
}

extension ScanBoardingPassViewController: AVCaptureMetadataOutputObjectsDelegate {


func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    // Check if the metadataObjects array is not nil and it contains at least one object.
    if metadataObjects.count == 0 {
        qrCodeFrameView?.frame = CGRect.zero
        debugPrint(BarcodeScanError.NoValidBarcode)
        return
    }
    
    // Get the metadata object.
    let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
    
    if supportedCodeTypes.contains(metadataObj.type) {
        // If the found metadata is equal to the QR code metadata (or barcode) then update the status label's text and set the bounds
        let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
        qrCodeFrameView?.frame = barCodeObject!.bounds
        
        
        if metadataObj.stringValue != nil {
            captureSession?.stopRunning()
            
            debugPrint("Valid Barcode found \(metadataObj.stringValue!)")
        if let boardingPass = viewModel?.parseBoardingPassString(boardingPassString : metadataObj.stringValue!) {
           

                let unitOfWork = UnitOfWork(context:( UIApplication.shared.delegate as! AppDelegate).persistentContainer.newBackgroundContext() )

                unitOfWork.boardingPassRepository.saveBoardingPasses(boardingPass: boardingPass)
                unitOfWork.saveChanges()
                print(unitOfWork.boardingPassRepository.getBoardingPasses(predicate: nil))
                self.dismissView()


               }
            }
        }
    }
   }

The camera doesnt get struck. But, the app gives an lldb everytime within a few seconds.

Akaanksha
  • 161
  • 1
  • 14

1 Answers1

-1
//  Created by Satya Narayana on 17/11/20.
//

import UIKit
import AVFoundation
import UIKit

class QRViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    //MARK: Outlets
    @IBOutlet weak var qrLbl: UILabel! // BarCode displaying Label
    @IBOutlet weak var sView: UIView!  // View
    
    //MARK: Variables
    var captureSession: AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer!
    
    
    //MARK: View Methods
    override func viewDidLoad() {
        super.viewDidLoad()

        captureSession = AVCaptureSession()

        guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
        let videoInput: AVCaptureDeviceInput

        do {
            videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
        } catch {
            return
        }

        if (captureSession.canAddInput(videoInput)) {
            captureSession.addInput(videoInput)
        } else {
            failed()
            return
        }

        let metadataOutput = AVCaptureMetadataOutput()

        if (captureSession.canAddOutput(metadataOutput)) {
            captureSession.addOutput(metadataOutput)
            metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            metadataOutput.metadataObjectTypes = [.qr, .ean13, .code128]
        } else {
            failed()
            return
        }

        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer.frame = sView.layer.bounds
        previewLayer.videoGravity = .resizeAspectFill
        sView.layer.addSublayer(previewLayer)

        captureSession.startRunning()
    }
   
    
 
    
    
    func failed() {
        self.showToast(message: "Scanning not supported.Your device does not support scanning a code from an item. Please use a device with a camera.", seconds: 1.0)
        captureSession = nil
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        qrLbl.isHidden = true
        if (captureSession?.isRunning == false) {
            captureSession.startRunning()
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        if (captureSession?.isRunning == true) {
            captureSession.stopRunning()
        }
    }

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        captureSession.stopRunning()
        if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
            guard let stringValue = readableObject.stringValue else { return }
            AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
            found(code: stringValue)
        }
        dismiss(animated: true)
    }

    //MARK:- Found BARCODE
    func found(code: String) {
        print(code)
        if code != ""{
        print(code) // This is Barcode
            qrLbl.text = code
        }else{
         // if you need run again uncomment below line
           //self.captureSession.startRunning()
                

        }
    }


    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}
  • 1
    While this code may provide a solution to the question, it's better to add context as to why/how it works. This can help future users learn, and apply that knowledge to their own code. You are also likely to have positive feedback from users in the form of upvotes, when the code is explained. – Amit Verma Jan 27 '21 at 09:11