我成功地做了自定义相机,与现场预览等,但是,当我试图捕捉照片这个错误出现:Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
这是我的密码
class CameraService {
var session: AVCaptureSession?
var delegate: AVCapturePhotoCaptureDelegate?
let output = AVCapturePhotoOutput()
let previewLayer = AVCaptureVideoPreviewLayer()
func start(delegate: AVCapturePhotoCaptureDelegate, completion:@escaping (Error?) -> ()) {
self.delegate = delegate
self.checkPermissions(completion: completion)
}
private func checkPermissions(completion:@escaping (Error?) -> ()){
switch AVCaptureDevice.authorizationStatus(for: .video){
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
guard granted else { return }
DispatchQueue.main.async {
self?.setupCamera(completion: completion)
}
}
case .restricted:
break
case .denied:
break
case .authorized:
setupCamera(completion: completion)
@unknown default:
break
}
}
private func setupCamera(completion:@escaping (Error?) -> ()) {
let session = AVCaptureSession()
if let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front){
do {
let input = try AVCaptureDeviceInput(device: device)
if session.canAddInput(input) {
session.addInput(input)
}
if session.canAddOutput(output) {
session.addOutput(output)
}
previewLayer.videoGravity = .resizeAspectFill
previewLayer.session = session
DispatchQueue.global(qos:.userInitiated).async {
session.startRunning()
}
self.session = session
} catch {
completion(error)
}
}
}
func capturePhoto(with settings: AVCapturePhotoSettings = AVCapturePhotoSettings()) {
output.capturePhoto(with: settings, delegate: delegate!) // This is where the
error comes up.
}
}
相机视图
struct CameraView: UIViewControllerRepresentable {
typealias UIViewControllerType = UIViewController
let cameraService: CameraService
let didFinishProcessingPhoto: (Result<AVCapturePhoto, Error>) -> ()
func makeUIViewController(context: Context) -> UIViewController {
cameraService.start(delegate: context.coordinator) { err in
if let err = err {
didFinishProcessingPhoto(.failure(err))
return
}
}
let viewController = UIViewController()
viewController.view.backgroundColor = .black
viewController.view.layer.addSublayer(cameraService.previewLayer)
cameraService.previewLayer.frame = viewController.view.bounds
return viewController
}
func makeCoordinator() -> Coordinator {
Coordinator(self, didFinishProcessingPhoto: didFinishProcessingPhoto)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
class Coordinator: NSObject, AVCapturePhotoCaptureDelegate {
let parent: CameraView
private var didFinishProcessingPhoto: (Result<AVCapturePhoto, Error>) -> ()
init(_ parent: CameraView,
didFinishProcessingPhoto: @escaping (Result<AVCapturePhoto, Error>) -> ()) {
self.parent = parent
self.didFinishProcessingPhoto = didFinishProcessingPhoto
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let error = error {
didFinishProcessingPhoto(.failure(error))
return
}
didFinishProcessingPhoto(.success(photo))
}
}
}
自定义相机视图
import SwiftUI
import AVFoundation
struct CustomCameraView: View {
let cameraService = CameraService()
@Binding var capturedImage: UIImage?
@Environment(\.presentationMode) private var presentationMode
var body: some View {
ZStack {
CameraView(cameraService: cameraService, didFinishProcessingPhoto: { result in
switch result {
case .success(let photo):
if let data = photo.fileDataRepresentation() {
capturedImage = UIImage(data: data)
} else {
print("Error: no image data found.")
}
case .failure(let err):
print(err.localizedDescription)
}
})
.frame(maxWidth:.infinity, maxHeight: .infinity)
.ignoresSafeArea()
VStack{
Button {
cameraService.capturePhoto()
} label: {
Circle()
.fill(.white)
.frame(width: 60, height:60)
}
}
}
}
}
我知道我需要安全地打开可选值,但我这样做只是因为它是用于测试目的。
我知道这是一个很大的代码,但我会很感激,如果有人看更接近的问题。
1条答案
按热度按时间tp5buhyn1#
这是一个错误:
它应该只是
Coordinator()
,因为self
和didFinish
将丢失,因为它位于将被多次重新初始化的结构体内部。此外,必须实现
updateUIViewController
,以便使用该结构体中的所有新值更新视图控制器和协调器。这是我制作的一个example,它可以帮助您正确使用。