为什么previewLayer在我尝试获取边界时返回nil?

问题描述:

此视图控制器正从另一个故事板上的按钮调用。我每次点击按钮,我得到为什么previewLayer在我尝试获取边界时返回nil?

fatal error: unexpectedly found nil while unwrapping an Optional value 2017-04-16 21:00:39.929042 FaceOnACase[757:377279] fatal error: unexpectedly found nil while unwrapping an Optional value

上线self.previewLayer?.frame = self.previewView.bounds。

我以前在单独的单一视图应用程序中工作时使用了此代码,但是当我将代码转移并连接IBOutlets时,出于某种原因无法使其工作。

我找不到类似的问题,我不确定如何解决此问题。任何帮助表示赞赏,谢谢。

import UIKit 
import AVFoundation 

class CaptureController: UIViewController, AVCapturePhotoCaptureDelegate { 
    var captureSesssion: AVCaptureSession! 
    var cameraOutput: AVCapturePhotoOutput! 
    var previewLayer: AVCaptureVideoPreviewLayer! 
    @IBOutlet weak var capturedImage: UIImageView! 
    @IBOutlet weak var previewView: UIView! 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     captureSesssion = AVCaptureSession() 
     captureSesssion.sessionPreset = AVCaptureSessionPresetPhoto 
     cameraOutput = AVCapturePhotoOutput() 
     let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 
     do { 
      let input = try AVCaptureDeviceInput(device: device) 
      if (captureSesssion.canAddInput(input)) { 
       captureSesssion.addInput(input) 
       if (captureSesssion.canAddOutput(cameraOutput)) { 
        captureSesssion.addOutput(cameraOutput) 
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSesssion) 
        self.previewLayer?.frame = self.previewView.bounds 
        previewView.layer.addSublayer(previewLayer) 
        captureSesssion.startRunning() 
       } 
      } else { 
       print("issue here : captureSesssion.canAddInput") 
      } 
     } catch let error { 
      print("error \(error.localizedDescription)") 
     } 
    } 
    // Take picture button 
    @IBAction func didPressTakePhoto(_ sender: UIButton) { 
     let settings = AVCapturePhotoSettings() 
     let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first! 
     let previewFormat = [ 
      kCVPixelBufferPixelFormatTypeKey as String: previewPixelType, 
      kCVPixelBufferWidthKey as String: 160, 
      kCVPixelBufferHeightKey as String: 160 
     ] 
     settings.previewPhotoFormat = previewFormat 
     cameraOutput.capturePhoto(with: settings, delegate: self) 
    } 
    // callBack from take picture 
    func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) { 
     if let error = error { 
      print("error occured : \(error.localizedDescription)") 
     } 
     if let sampleBuffer = photoSampleBuffer, 
      let previewBuffer = previewPhotoSampleBuffer, 
      let dataImage = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: previewBuffer) { 
      print(UIImage(data: dataImage)?.size as Any) 
      let dataProvider = CGDataProvider(data: dataImage as CFData) 
      let cgImageRef: CGImage! = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent) 
      let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right) 
      self.capturedImage.image = image 
     } else { 
      print("some error here") 
     } 
    } 
    // This method you can use somewhere you need to know camera permission state 
    func askPermission() { 
     print("here") 
     let cameraPermissionStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) 
     switch cameraPermissionStatus { 
     case .authorized: 
      print("Already Authorized") 
     case .denied: 
      print("denied") 
      let alert = UIAlertController(title: "Sorry :(" , message: "But could you please grant permission for camera within device settings", preferredStyle: .alert) 
      let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil) 
      alert.addAction(action) 
      present(alert, animated: true, completion: nil) 
     case .restricted: 
      print("restricted") 
     default: 
      AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { 
       [weak self] 
       (granted :Bool) -> Void in 
       if granted == true { 
        // User granted 
        print("User granted") 
        DispatchQueue.main.async(){ 
         //Do smth that you need in main thread 
        } 
       } 
       else { 
        // User Rejected 
        print("User Rejected") 
        DispatchQueue.main.async(){ 
         let alert = UIAlertController(title: "WHY?" , message: "Camera it is the main feature of our application", preferredStyle: .alert) 
         let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil) 
         alert.addAction(action) 
         self?.present(alert, animated: true, completion: nil) 
        } 
       } 
      }) 
     } 
    } 
} 

previewLayer返回nil。它是previewViewnil。确保你已经正确地将它连接到故事板上的插座。

另外你在做什么还为时过早。您无法在viewDidLoad开始捕获会话。请记住,这意味着视图存在,但它甚至不在界面中!您至少需要一个接口才能启动捕获会话。

+0

好的,我检查了一下,我把它连接好了。现在,我应该把它们放在viewWillAppear而不是viewDidLoad中吗? – David

+0

因为现在一切似乎都正常。谢谢btw! – David

+0

我会建议使用'viewDidLayoutSubviews',因为你依赖'self.previewView.bounds',直到那时它才会正确设置。您将需要一个Bool标志,以便您的代码只运行一次(因为viewDidLayoutSubviews被多次调用)。 – matt