2016-12-19 11 views
1

Ich habe eine App, die Barcodes liest. Wenn ein Barcode erkannt wird, verwendet er eine API, um Informationen über die erkannten Metadaten zu erhalten. Das Problem ist, dass es bei jedem Scan den Barcode 30-40 Mal liest, was ein Problem sein kann, da ich nur 1000 API-Aufrufe pro Stunde machen darf.Wie kann die Anzahl der API-Aufrufe begrenzt werden?

Gibt es eine einfache Möglichkeit, die Scanning- oder API-Aufrufe zu "pausieren", wenn einer bearbeitet wird?

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() 
} 

Antwort

6

Nachdem Sie den Barcode erfasst, in dem if metadataObj.stringValue != nil Block, sollten Sie entweder den Delegaten auf Null oder captureSession auf Null, die das Scannen temperately zu stoppen (sonst hält es Scannen). Nachdem Sie die API aufgerufen und zurückgegeben haben, können Sie die Sitzung erneut starten, wenn Sie einen weiteren Scan durchführen möchten.

+1

Weiter würde ich vorschlagen, dass Sie ein Wörterbuch oder eine 'NSCache'-Instanz verwenden, um die abgerufenen Daten zu speichern. Auf diese Weise können Sie den API-Aufruf vermeiden, auch wenn Sie nach dem erneuten Aktivieren des Scans denselben Barcode erneut scannen. – Paulw11

+0

Danke, es hat funktioniert! – Jake

0

Die obige Antwort ist korrekt, ich habe die Erfassungssitzung gestoppt, als ein Barcode erkannt wurde, und dies schien einen Aufruf pro Barcode-Scan zu begrenzen.

if metadataObj.stringValue != nil { 
    messageLabel.text = metadataObj.stringValue 
    barcodeString = (metadataObj.stringValue) 
    barcodeString.remove(at: barcodeString.startIndex) 
    self.readCode(barcodeString: barcodeString) 
    captureSession?.stopRunning() 
    } 
Verwandte Themen