英文:
Delegate found nil while trying to capture the photo
问题
我成功地创建了自定义相机,包括实时预览等等。但是,当我尝试拍照时,出现了以下错误:
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!) // 这是发生错误的地方。
}
}
struct CameraView: UIViewControllerRepresentable {
// ...
}
struct CustomCameraView: View {
// ...
}
我知道我需要安全解包可选值,但我只是为了测试目的才这样做。这是很多代码,但如果有人仔细查看问题,我将不胜感激。
英文:
I successfully made custom camera, with live preview etc. but, when I try to capture the photo this error comes up:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
This is my code
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.
}
}
CameraView
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))
}
}
}
CustomCameraView
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)
}
}
}
}
}
I know that I need to safe unwrap the optional value, but I did this only because it's for testing purpose.
I know this is a lot of code, but I would be grateful if someone looks closer to the question.
答案1
得分: 1
这是一个错误:
func makeCoordinator() -> Coordinator {
Coordinator(self, didFinishProcessingPhoto: didFinishProcessingPhoto)
}
应该只是 Coordinator()
,因为 self
和 didFinish
将会丢失,因为这在一个将被多次重新初始化的结构体内。
此外,实现 updateUIViewController
是必不可少的,以便使用此结构体中的所有新值更新视图控制器和协调器。
这是一个我制作的示例,可以帮助你弄对。
英文:
This is a mistake:
func makeCoordinator() -> Coordinator {
Coordinator(self, didFinishProcessingPhoto: didFinishProcessingPhoto)
}
It should just be Coordinator()
, because self
and that didFinish
will be lost since this is inside of a struct that will be re-init many times.
Also, it is essential to implement updateUIViewController
to update both the view controller and the coordinator with all the new values in this struct.
Here is an example I made to help you get it right.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论