【发布时间】:2017-02-09 15:50:35
【问题描述】:
我试图从我的视图控制器中提取一些代码来清理它并尽可能保持为 DRY 代码。在以下情况下可以正常工作:
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
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!
}
}
我在 InitialRegistrationViewController 中调用的位置:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
profilePhoto.startSession()
}
func capturePhoto() {
profileImage.image = profilePhoto.capture()
}
在 profilePhoto.capture() 中返回图像时,我得到 fatal error: unexpectedly found nil while unwrapping an Optional value。
我不明白会话是如何像 ios 新手一样工作的,但我认为这是因为当我尝试捕获图像时会话正在结束(?)?任何见解都会很棒。谢谢
更新:我赞成给出的答案足够接近,以下对我有用。
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)
}
}
【问题讨论】:
-
正如方法名称所述,图像是异步捕获的。见:stackoverflow.com/questions/31794542/…
-
@dan 我明白了,我也查看了您提供的其他链接,但我不知道如何将它应用到我的代码中?会喜欢另一个提示。谢谢
标签: ios swift avcapturesession