iosswiftrsbarcodes

Perform Action When a Barcode Is Scanned Using RSBarcodes


I am building an app that utilizes QR code scanning using RSBarcodes for Swift. What I am trying to do in my ScanViewController is to scan a QR code, validate what was scanned, and then segue with the scanned data. Currently, when a QR code is detected, my UI freezes, and shortly after I get an error and memory dump:

'NSInternalInconsistencyException', reason: 'Only run on the main thread!'.

Maybe this isn't the right place to validate the QR code or isn't the right place to segue, but if not, I'm wondering where the validation and segue should take place. My only other requirement is that the validation only occurs exactly when a QR code is detected.

class ScanViewController: RSCodeReaderViewController{
    // Class Variables
    var finalObject: IBuiltCode?
    let ObjectHelper = ObjectBuilder() // Service to validate and build valid scanned objects

    override func viewDidLoad() {
        super.viewDidLoad()

        self.focusMarkLayer.strokeColor = UIColor.redColor().CGColor
        self.cornersLayer.strokeColor = UIColor.yellowColor().CGColor

        self.tapHandler = { point in
            println(point)
        }

        self.barcodesHandler = { barcodes in
            for barcode in barcodes {
                println("Barcode found: type=" + barcode.type + " value=" + barcode.stringValue)
                if let builtObject = self.ObjectHelper.validateAndBuild(barcode,
                      scannedData: barcode.stringValue){
                    println("Good object.")
                    self.performQR()
                }
            }
        }
    }

    func performQR(){
        performSegueWithIdentifier("toQR", sender: self)
    }
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if (segue.identifier == "toQR"){
            let QRVC: QRViewController = segue.destinationViewController as! QRViewController
            QRVC.receivedObject = finalObject as? QRObject
        }
    }
}

Solution

  • I contacted the developer of RSBarcodes_Swift on this issue thread. In order for any UI operation to execute, it needs to be run on the main thread. For example, the segue function needs to be changed from:

    func performQR(){
            self.performSegueWithIdentifier("toQR", sender: self)
    }
    

    to

    func performQR(){
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.performSegueWithIdentifier("toQR", sender: self)
        })
    }
    

    To avoid segueing multiple times while scanning, the call self.session.stopRunning() along with a breakcan be used in the barcodes for loop.

    self.barcodesHandler = { barcodes in
        for barcode in barcodes {
            println("Barcode found: type=" + barcode.type + " value=" + barcode.stringValue)
            if let builtObject = self.ObjectHelper.validateAndBuild(barcode,
                  scannedData: barcode.stringValue){
                println("Good object.")
                self.finalObject = builtObject
                self.session.stopRunning() // Avoid scanning multiple times
                self.performQR()
                break
            }
        }
    }