I'm creating an app that uses the new barcode scanner in iOS 7 but I'm having a some problems with the delegate method. The scanner correctly identifies the barcodes and invokes the delegate method, but it does it too fast so the invocation happens many times in a row resulting in a segue being performed multiple times. Delegate method below.
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
connection.enabled = NO;
self.conn = connection;
for (AVMetadataObject *metadata in metadataObjects) {
if ([metadata.type isEqualToString:AVMetadataObjectTypeEAN8Code] || [metadata.type isEqualToString:AVMetadataObjectTypeEAN13Code]) {
self.strValue = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
NSLog(@"%@", [(AVMetadataMachineReadableCodeObject *)metadata corners]);
}
}
[self performSegueWithIdentifier:@"newSegue" sender:self];
}
The issue is that if I do not set connection.enabled = NO
in the opening line, the delegate is invoked multiple times causing a corrupt view hierarchy (and then a crash). The other issue is that when I do disable connection and then re-enable the connection using self.conn = YES
in viewWillAppear, the delegate will be invoked repeatedly from prior scans when returning to the view. This then causes another corruption in the view hierarchy.
So to sum it up: Either the delegate method is being invoked multiple times in quick succession or the delegate is being invoked with (old) scans when returning to the view. Any help would be appreciated.
Edit: I've partially managed to get around the problem with some fidgeting with the delegate, but I still have a problem with the delegate method being invoked multiple times. If you go back from the next viewcontroller in less than five seconds, the delegate method will be invoked again.
I think you have started captureSession using captureSession?.startRunning() method but didn't stop it once you got output from QRCode in delegate...
Just Use this [captureSession stopRunning]; // In Objective-C
below is what I have done for same issue in swift
// MARK: - AVCapture delegate to find metadata if detected
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
// Check if the metadataObjects array is not nil and it contains at least one object.
if metadataObjects == nil || metadataObjects.count == 0 {
qrCodeFrameView?.frame = CGRectZero
return
}
// Get the metadata object.
let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
if metadataObj.type == AVMetadataObjectTypeQRCode {
// If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds
let barCodeObject = videoPreviewLayer?.transformedMetadataObjectForMetadataObject(metadataObj as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject
qrCodeFrameView?.frame = barCodeObject.bounds;
if metadataObj.stringValue != nil {
captureSession?.stopRunning() // Stop captureSession here... :)
self.performSegueWithIdentifier("yourNextViewController", sender: self)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With