2016-09-17 109 views
9

我正在关注tutorial,并试图将代码格式从Swift 2.0转换为3.0。但是当我启动应用程序时,该应用程序不起作用!我的意思是,没有反应!这里是我的代码:使用AVFoundation扫描Swift 3.0中的条码或QR码

的ViewController:

class ViewController: UIViewController ,BarcodeDelegate { 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 

     let barcodeViewController: BarcodeViewController = segue.destination as! BarcodeViewController 
     barcodeViewController.delegate = self 

    } 



    func barcodeReaded(barcode: String) { 
     codeTextView.text = barcode 
     print(barcode) 
    } 

} 

BarcodeVC:

import AVFoundation 


protocol BarcodeDelegate { 

    func barcodeReaded(barcode: String) 
} 

class BarcodeViewController: UIViewController,AVCaptureMetadataOutputObjectsDelegate { 

    var delegate: BarcodeDelegate? 
    var captureSession: AVCaptureSession! 
    var code: String? 


    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Do any additional setup after loading the view. 
     print("works") 

     self.captureSession = AVCaptureSession(); 
     let videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 

     do { 

      let videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) 

      if self.captureSession.canAddInput(videoInput) { 
       self.captureSession.addInput(videoInput) 
      } else { 
       print("Could not add video input") 
      } 

      let metadataOutput = AVCaptureMetadataOutput() 
      if self.captureSession.canAddOutput(metadataOutput) { 
       self.captureSession.addOutput(metadataOutput) 

       metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) 
       metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code] 
      } else { 
       print("Could not add metadata output") 
      } 

      let previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession) 
      previewLayer?.frame = self.view.layer.bounds 
      self.view.layer .addSublayer(previewLayer!) 
      self.captureSession.startRunning() 
     } catch let error as NSError { 
      print("Error while creating vide input device: \(error.localizedDescription)") 
     } 



    } 



    //I THINK THIS METHOD NOT CALL ! 
    private func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { 

     // This is the delegate'smethod that is called when a code is readed 
     for metadata in metadataObjects { 
      let readableObject = metadata as! AVMetadataMachineReadableCodeObject 
      let code = readableObject.stringValue 

      // If the code is not empty the code is ready and we call out delegate to pass the code. 
      if code!.isEmpty { 
       print("is empty") 

      }else { 

       self.captureSession.stopRunning() 
       self.dismiss(animated: true, completion: nil) 
       self.delegate?.barcodeReaded(barcode: code!) 


      } 
     } 

    } 

这里是输出:

2016年9月17日18: 10:26.000919 BarcodeScaning [2610:674253] [MC] systemgroup.com.apple.configurationprofiles路径的系统组容器路径为/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles 2016-09-17 18:10:26.007782 BarcodeScaning [2610 :674253] [MC]从公共有效用户设置读取。

+0

AVCaptureMetadataOutputObjectsDelegate的方法见我的答案,如果你需要完整的代码,我可以使其可在Github上 –

+0

条码阅读器在swift 3.0中:https://iosdevcenters.blogspot.com/2017/09/building-barcode-and-qr-code-reader-in.html –

回答

17

第一步需要声明访问任何用户私人数据类型,这是iOS 10中的一项新需求。您可以通过向应用程序的Info.plist添加使用密钥以及目标字符串来完成此操作。

因为如果你使用的是下列框架之一,未能申报使用时,它第一次访问您的应用程序会崩溃:

联系人,日历,提醒,照片,蓝牙共享,麦克风,相机,位置,健康,HomeKit,媒体库,Motion,CallKit,语音识别,SiriKit,电视提供商。

为避免你需要建议的键添加到Info.plist崩溃:

enter image description here

,然后系统显示的目的串,要求用户允许访问时:

enter image description here

欲了解更多信息,你可以使用它这篇文章:

我做了一些修改,您BarcodeViewController,使其正常工作,你可以看到如下:

BarcodeViewController

import UIKit 
import AVFoundation 

protocol BarcodeDelegate { 
    func barcodeReaded(barcode: String) 
} 

class BarcodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { 

    var delegate: BarcodeDelegate? 

    var videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 
    var device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 
    var output = AVCaptureMetadataOutput() 
    var previewLayer: AVCaptureVideoPreviewLayer? 

    var captureSession = AVCaptureSession() 
    var code: String? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     self.view.backgroundColor = UIColor.clear 
     self.setupCamera() 
    } 

    private func setupCamera() { 

     let input = try? AVCaptureDeviceInput(device: videoCaptureDevice) 

     if self.captureSession.canAddInput(input) { 
      self.captureSession.addInput(input) 
     } 

     self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 

     if let videoPreviewLayer = self.previewLayer { 
      videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill 
      videoPreviewLayer.frame = self.view.bounds 
      view.layer.addSublayer(videoPreviewLayer) 
     } 

     let metadataOutput = AVCaptureMetadataOutput() 
     if self.captureSession.canAddOutput(metadataOutput) { 
      self.captureSession.addOutput(metadataOutput) 

      metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) 
      metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code] 
     } else { 
      print("Could not add metadata output") 
     } 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 

     if (captureSession.isRunning == false) { 
      captureSession.startRunning(); 
     } 
    } 

    override func viewWillDisappear(_ animated: Bool) { 
     super.viewWillDisappear(animated) 

     if (captureSession.isRunning == true) { 
     captureSession.stopRunning(); 
     } 
    } 

    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { 
     // This is the delegate'smethod that is called when a code is readed 
     for metadata in metadataObjects { 
      let readableObject = metadata as! AVMetadataMachineReadableCodeObject 
      let code = readableObject.stringValue 


      self.dismiss(animated: true, completion: nil) 
      self.delegate?.barcodeReaded(barcode: code!) 
      print(code!) 
     } 
    } 
} 

其中一个重要的点是声明全局变量,并在viewWillAppear(:)viewWillDisappear(:)方法内启动和停止captureSession。在你之前的代码中,我认为它根本没有被调用,因为它从不进入处理条形码的方法。

我希望这对你有所帮助。

+1

谢谢维克多!它工作正常 –

+0

我将奖励1H(由于局限)赏金 –

+0

@ Mc.Lover没问题,:) –

0

您需要将NSCameraUsageDescription添加到Info.plist文件才能使其正常工作!

只需在info.plist中添加一行,并键入NSCameraUsageDescription到新创建的行和增加意味着告发为什么你的应用程序中需要访问摄像机的用户串

这应该是诀窍!

+0

我加了!仍然不工作,相机打开,但没有qr或条码检测 –

+0

是的,现在得到了同样的问题!首先,我只是将提供给Swift 3语法的完整项目进行了转换,并添加了NSCameraUsageDescription - 像魅力一样工作。 现在继教程后,我被困在同样的问题......不知道什么是交易,但我会继续寻找。 –

0
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { 
    print("caught QR code") 
    for metadata in metadataObjects { 
    let readableObject = metadata as! AVMetadataMachineReadableCodeObject 
    let code = readableObject.stringValue 
    if code!.isEmpty { 
     print("is empty") 
    } else { 
     self.captureSession.stopRunning() 
     self.dismiss(animated: true, completion: nil) 
     self.delegate?.gotQRCode(code: code!) 
    } 
    } 
} 

貌似方法的签名在斯威夫特3.修改一下下面是正确的版本

2

下面是Victor Sigler's answer更新为斯威夫特4没有力量展开,弱协议及其他改进。

注意,从

captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) 

改为

metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) 

import UIKit 
import AVFoundation 

protocol BarcodeDelegate: class { 
    func barcodeRead(barcode: String) 
} 

class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { 
    weak var delegate: BarcodeDelegate? 

    var output = AVCaptureMetadataOutput() 
    var previewLayer: AVCaptureVideoPreviewLayer! 

    var captureSession = AVCaptureSession() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupCamera() 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 

     if !captureSession.isRunning { 
      captureSession.startRunning() 
     } 
    } 

    override func viewWillDisappear(_ animated: Bool) { 
     super.viewWillDisappear(animated) 

     if captureSession.isRunning { 
      captureSession.stopRunning() 
     } 
    } 

    private func setupCamera() { 
     guard let device = AVCaptureDevice.default(for: .video), 
      let input = try? AVCaptureDeviceInput(device: device) else { 
      return 
     } 

     if captureSession.canAddInput(input) { 
      captureSession.addInput(input) 
     } 

     previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 
     previewLayer.videoGravity = .resizeAspectFill 
     previewLayer.frame = view.bounds 
     view.layer.addSublayer(previewLayer) 

     let metadataOutput = AVCaptureMetadataOutput() 

     if captureSession.canAddOutput(metadataOutput) { 
      captureSession.addOutput(metadataOutput) 

      metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) 
      metadataOutput.metadataObjectTypes = [.qr, .ean13] 
     } else { 
      print("Could not add metadata output") 
     } 
    } 

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 
     // This is the delegate's method that is called when a code is read 
     for metadata in metadataObjects { 
      if let readableObject = metadata as? AVMetadataMachineReadableCodeObject, 
       let code = readableObject.stringValue { 
       dismiss(animated: true) 
       delegate?.barcodeRead(barcode: code) 
       print(code) 
      } 
     } 
    } 
} 
+0

The注意关于对AVCaptureMetadataOutputObjectsDelegate的更改确实帮助了我,谢谢 –