2017-02-09 7 views
0

私のビューコントローラからコードを抽出して、DRYを可能なコードとして維持しています。次のようにするときには正常に動作します:AvCaptureSessionコード抽出エラー

class InitialRegistrationViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, NVActivityIndicatorViewable { 

    var session: AVCaptureSession? 
    var stillImageOutput: AVCaptureStillImageOutput? 

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

     if Platform.isPhone { 
      session = AVCaptureSession() 
      session!.sessionPreset = AVCaptureSessionPresetPhoto 

      var frontCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 
      let availableCameraDevices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) 
      for device in availableCameraDevices as! [AVCaptureDevice] { 
       if device.position == .front { 
        frontCamera = device 
       } 
      } 

      var error: NSError? 
      var input: AVCaptureDeviceInput! 
      do { 
       input = try AVCaptureDeviceInput(device: frontCamera) 
      } catch let error1 as NSError { 
       error = error1 
       input = nil 
       print(error!.localizedDescription) 
      } 

      if error == nil && session!.canAddInput(input) { 
       session!.addInput(input) 
       stillImageOutput = AVCaptureStillImageOutput() 
       stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] 

       if session!.canAddOutput(stillImageOutput) { 
        session!.addOutput(stillImageOutput) 
        session!.startRunning() 
       } 
      } 
     } 
    } 


    func capturePhoto() { 
     if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) { 
      stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in 
       if sampleBuffer != nil { 
        let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) 
        let dataProvider = CGDataProvider(data: imageData as! CFData) 
        let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) 
        let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.right) 
        self.profileImage.image = image 
       } 
      }) 
     } 
    } 
} 

しかし、私は以下のようなヘルパーに抽出します。

輸入のUIKit 輸入AVFoundation InitialRegistrationViewControllerに私が呼ん

class ProfilePhoto { 

    var session: AVCaptureSession? 
    var stillImageOutput: AVCaptureStillImageOutput? 

    func startSession() { 

     if Platform.isPhone { 
      session = AVCaptureSession() 
      session!.sessionPreset = AVCaptureSessionPresetPhoto 

      var frontCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 
      let availableCameraDevices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) 
      for device in availableCameraDevices as! [AVCaptureDevice] { 
       if device.position == .front { 
        frontCamera = device 
       } 
      } 

      var error: NSError? 
      var input: AVCaptureDeviceInput! 
      do { 
       input = try AVCaptureDeviceInput(device: frontCamera) 
      } catch let error1 as NSError { 
       error = error1 
       input = nil 
       print(error!.localizedDescription) 
      } 

      if error == nil && session!.canAddInput(input) { 
       session!.addInput(input) 
       stillImageOutput = AVCaptureStillImageOutput() 
       stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] 

       if session!.canAddOutput(stillImageOutput) { 
        session!.addOutput(stillImageOutput) 
        session!.startRunning() 
       } 
      } 
     } 
    } 

    func capture() -> UIImage { 
     var image: UIImage! 

     if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) { 
      stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in 
       if sampleBuffer != nil { 
        let cgImageRef = self.setBufferData(sampleBuffer: sampleBuffer!) 
        image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right) 
       } 
      }) 
     } 
     return image 
    } 

    func setBufferData(sampleBuffer: CMSampleBuffer) -> CGImage { 
     let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) 
     let dataProvider = CGDataProvider(data: imageData as! CFData) 
     let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) 
     return cgImageRef! 
    } 
} 

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

    profilePhoto.startSession() 
} 


func capturePhoto() { 
    profileImage.image = profilePhoto.capture() 
} 

fatal error: unexpectedly found nil while unwrapping an Optional value whe nはprofilePhoto.capture()で画像を返します。

私はセッションがiosに新しいものとして機能するのを理解していませんが、画像をキャプチャしようとするとセッションが終了しているので(?)どんな洞察も素晴らしいだろう。ありがとう

更新:私は十分に近いと答えたupvotes、以下は私のために働いたものです。

func capture(completion: @escaping (UIImage?) -> Void) { 

    if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) { 
     stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in 
      if sampleBuffer != nil { 
       let cgImageRef = self.setBufferData(sampleBuffer: sampleBuffer!) 
       let image: UIImage! = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right) 
       completion(image) 
      } else { 
       completion(nil) 
      } 
     }) 
    } else { 
     completion(nil) 
    } 
} 
+1

メソッド名の状態に応じて、イメージは非同期にキャプチャされます。参照してください:http://stackoverflow.com/questions/31794542/ios-swift-function-that-returns-asynchronously-retrieved-value – dan

+0

@ダン私は、あなたも提供した他のリンクを見て、私のコードにそれを適用する?別のヒントが大好きです。お返事ありがとう – Wazza

答えて

1

あなたのキャプチャ()メソッドは、UIImageを取得するために非同期呼び出しを行うため、その戻り値は常にnilある[ただちに]を返すとき。

@danの記事は、画像を呼び出し元に返すために使用できるコールバックパターンを示しています。処理を進める前にこのメカニズムを理解していることを確認してください。

func capture(result: (image: UIImage?) -> Void) -> UIImage 
    { 
     if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) 
     { 
      stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: 
      { (sampleBuffer, error) -> Void in 

      if sampleBuffer != nil 
      { 
       let cgImageRef = self.setBufferData(sampleBuffer: sampleBuffer!) 
       var image: UIImage! = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right) 
       result(image: image) 
      } 
      else 
       result(image: nil) 

      }) 
     } 
     else 
      result(image: nil) 
    } 

そして、それを呼び出すために、あなたは

capture(){(image: UIImage?) -> Void in 
    //use the image that was just retrieved 
} 

を使用することができます今、あなたのキャプチャ()メソッドを非同期に行われ、コールバックを介して、その戻り値を報告しました。

+0

返信いただき、ありがとうございましたあなたの回答を怒らせるために苦労していますが、私はそれを修正する方法を理解しているようです。いくつか不足している/余分な括弧があるようですか? – Wazza

+0

私は不足している角括弧を追加したと思いますが、私は質問に更新コードを入れましたが、まだ何かを返さないというエラーが返ってきました。何か案は? – Wazza

関連する問題