ios 代表在尝试捕获照片时发现nil

ecfsfe2w  于 2023-03-05  发布在  iOS
关注(0)|答案(1)|浏览(144)

我成功地做了自定义相机,与现场预览等,但是,当我试图捕捉照片这个错误出现:
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)
                }
            }
        }
    }
}

我知道我需要安全地打开可选值,但我这样做只是因为它是用于测试目的。
我知道这是一个很大的代码,但我会很感激,如果有人看更接近的问题。

tp5buhyn

tp5buhyn1#

这是一个错误:

func makeCoordinator() -> Coordinator {
    Coordinator(self, didFinishProcessingPhoto: didFinishProcessingPhoto)
}

它应该只是Coordinator(),因为selfdidFinish将丢失,因为它位于将被多次重新初始化的结构体内部。
此外,必须实现updateUIViewController,以便使用该结构体中的所有新值更新视图控制器和协调器。
这是我制作的一个example,它可以帮助您正确使用。

相关问题