这是ViewController文件。我在这里按照教程: https://www.appcoda.com/avfoundation-swift-guide/
我不明白错误:
“条件绑定的初始化程序必须具有可选类型,而不是'[AVCaptureDevice]'”
和
“可选类型的值'AVCapturePhotoOutput?'没打开;你的意思是用'!'还是'?'?“
这些错误意味着什么?我该如何修理它们?
//
// CameraController.swift
// AV Foundation
//
// Created by ben on 5/10/18.
// Copyright © 2018 Pranjal Satija. All rights reserved.
//
import Foundation
import AVFoundation
import UIKit
class CameraController {
var previewLayer: AVCaptureVideoPreviewLayer?
var captureSession: AVCaptureSession?
var currentCameraPosition: CameraPosition?
var frontCamera: AVCaptureDevice?
var frontCameraInput: AVCaptureDeviceInput?
var photoOutput: AVCapturePhotoOutput?
var rearCamera: AVCaptureDevice?
var rearCameraInput: AVCaptureDeviceInput?
}
extension CameraController {
func displayPreview(on view: UIView) throws {
guard let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing }
self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.previewLayer?.connection?.videoOrientation = .portrait
view.layer.insertSublayer(self.previewLayer!, at: 0)
self.previewLayer?.frame = view.frame
}
func prepare(completionHandler: @escaping (Error?) -> Void) {
func createCaptureSession() {
self.captureSession = AVCaptureSession()
}
func configureCaptureDevices() throws {
let session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
guard let cameras = (session.devices.flatMap { $0 }), !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable }
for camera in cameras {
if camera.position == .front {
self.frontCamera = camera
}
if camera.position == .back {
self.rearCamera = camera
try camera.lockForConfiguration()
camera.focusMode = .autoFocus
camera.unlockForConfiguration()
}
}
}
func configureDeviceInputs() throws {
guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
if let rearCamera = self.rearCamera {
self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) }
self.currentCameraPosition = .rear
}
else if let frontCamera = self.frontCamera {
self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) }
else { throw CameraControllerError.inputsAreInvalid }
self.currentCameraPosition = .front
}
else { throw CameraControllerError.noCamerasAvailable }
}
func configurePhotoOutput() throws {
guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
self.photoOutput = AVCapturePhotoOutput()
self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecJPEG])], completionHandler: nil)
if captureSession.canAddOutput(self.photoOutput) { captureSession.addOutput(self.photoOutput) }
captureSession.startRunning()
}
DispatchQueue(label: "prepare").async {
do {
createCaptureSession()
try configureCaptureDevices()
try configureDeviceInputs()
try configurePhotoOutput()
}
catch {
DispatchQueue.main.async {
completionHandler(error)
}
return
}
DispatchQueue.main.async {
completionHandler(nil)
}
}
}
}
extension CameraController {
enum CameraControllerError: Swift.Error {
case captureSessionAlreadyRunning
case captureSessionIsMissing
case inputsAreInvalid
case invalidOperation
case noCamerasAvailable
case unknown
}
public enum CameraPosition {
case front
case rear
}
}
答案 0 :(得分:1)
在您的一条评论中,您最终指出哪条线导致错误:
guard let cameras = (session.devices.flatMap { $0 }), !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable }
这有几个问题。正如您在Swift手册的Control Flow - Early Exit部分中所看到的,guard let
用于验证可选变量不是nil
。
错误告诉您表达式(session.devices.flatMap { $0 })
不是可选的。实际上,这里使用flatMap
毫无意义,因为session.devices
是一个非可选值数组([AVCaptureDevice]]
)。
您应该将guard
重写为:
guard !session.devices.isEmpty else {
throw CameraControllerError.noCamerasAvailable
}
然后循环变为:
for camera in session.devices {