Reputation: 861
I have an app that reads barcodes. If a barcode is detected, it uses an API to get information about the metadata detected. The problem is that on each scan, it actually reads the barcode 30-40 times, which can be a problem as I am only allowed to make 1000 API calls per hour.
Is there an easy way to 'pause' the scanning or API calls when one is being processed?
override func viewDidLoad() {
super.viewDidLoad()
// Get an instance of the AVCaptureDevice class to initialize a device object and provide the video as the media type parameter.
let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
let yellow1 = UIColor(red: 0.427, green: 0.429, blue: 0.144, alpha: 1.0)
do {
// Get an instance of the AVCaptureDeviceInput class using the previous device object.
let input = try AVCaptureDeviceInput(device: captureDevice)
// Initialize the captureSession object.
captureSession = AVCaptureSession()
// 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
// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
// Start video capture.
captureSession?.startRunning()
view.bringSubview(toFront: messageLabel)
view.bringSubview(toFront: leftBracket)
view.bringSubview(toFront: rightBracket)
// Initialize QR Code Frame to highlight the QR code
qrCodeFrameView = UIView()
if let qrCodeFrameView = qrCodeFrameView {
qrCodeFrameView.layer.borderColor = yellow1.cgColor
qrCodeFrameView.layer.borderWidth = 2
view.addSubview(qrCodeFrameView)
view.bringSubview(toFront: qrCodeFrameView)
}
} catch {
// If any error occurs, simply print it out and don't continue any more.
print(error)
return
}
// Do any additional setup after loading the view.
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from 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 = CGRect.zero
messageLabel.text = "No barcode detected"
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 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 {
messageLabel.text = metadataObj.stringValue
barcodeString = (metadataObj.stringValue)
barcodeString.remove(at: barcodeString.startIndex)
self.readCode(barcodeString: barcodeString)
}
}
}
func readCode(barcodeString: String){
let string = "https://api.nal.usda.gov/ndb/search/?format=json&q=" + barcodeString + "&sort=n&max=25&offset=0&api_key=NY4LT5Gtc9X4eOOm40UBuSqfaO2eUgcwz20jIQLn"
let url = URL(string: string)
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("object not in database")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let array = json as NSDictionary
if array["list"] != nil{
let list = array["list"] as! [String : AnyObject]
let item = list["item"] as! NSArray
let dict = item[0] as! [String : AnyObject]
let num = dict["ndbno"] as! String
// Second API call
self.secondAPICall(number: num)
}
else{
// DO THIS IF ITEM NOT IN DATABASE
self.itemNotInDatabase()
}
}catch let error as NSError{
print(error)
}
}
}).resume()
}
Upvotes: 1
Views: 340
Reputation: 861
The answer above is correct, I stopped the capture session when a barcode was detected, and this seemed to limit one call per barcode scan.
if metadataObj.stringValue != nil {
messageLabel.text = metadataObj.stringValue
barcodeString = (metadataObj.stringValue)
barcodeString.remove(at: barcodeString.startIndex)
self.readCode(barcodeString: barcodeString)
captureSession?.stopRunning()
}
Upvotes: 0
Reputation: 1319
After you successfully captured the barcode, in the if metadataObj.stringValue != nil
block, you should either set the delegate to nil or captureSession
to nil, that will stop the scanning temperately(otherwise, it keeps scanning). After you called the api and it returned, you can start the session again, if you want to have another scan.
Upvotes: 6