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.
The workaround is to add to the delegate class a Boolean property that is switched to false after the first identification of a capture barcode event.
This solution is implemented as Calin Chitu offered.
You'll also need to initialize the property shouldSendReadBarcodeToDelegate once with YES.
The boolean property doesn't do the trick for me. I've ended using an operation queue to avoid multiple reads:
Initializing the queue in the viewcontroller constructor:
Doro's answer is good ,but has bug: function 'stopReading' may not be called in time before the delegate method is invoked second times
So i do some optimization.
based on Doro's answer, i add a Static variable to tell them .
I hope, it will save other's time. Here is article, how to use bar code scanner http://www.appcoda.com/qr-code-ios-programming-tutorial/
From the Apple documentation: "this method may be called frequently, your implementation should be efficient to prevent capture performance problems, including dropped metadata objects."
Now, to handle multiple invoke do the following :
the stopReading: method looks (assuming your _session is AVCaptureSession object and _prevLayer is AVCaptureVideoPreviewLayer you used earlier) :
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