我正在按照本教程为我的应用程序创建自定义相机。捕获图片后,用户可以继续到显示图像的另一个视图。不幸的是,有时图像根本不显示在下一页上,而其他时候却工作得很好。看来我的委托函数并没有一直被调用:
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {...}
我的相机型号
class CameraModel: NSObject,ObservableObject,AVCapturePhotoCaptureDelegate{
@Published var isTaken = false
@Published var session = AVCaptureSession()
@Published var alert = false
// since were going to read pic data....
@Published var output = AVCapturePhotoOutput()
// preview....
@Published var preview : AVCaptureVideoPreviewLayer!
@Published var image = UIImage()
func Check(){
// first checking camerahas got permission...
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
setUp()
return
// Setting Up Session
case .notDetermined:
// retusting for permission....
AVCaptureDevice.requestAccess(for: .video) { (status) in
if status{
self.setUp()
}
}
case .denied:
self.alert.toggle()
return
default:
return
}
}
func setUp(){
// setting up camera...
do{
// setting configs...
self.session.beginConfiguration()
// change for your own...
let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
let input = try AVCaptureDeviceInput(device: device!)
// checking and adding to session...
if self.session.canAddInput(input){
self.session.addInput(input)
}
// same for output....
if self.session.canAddOutput(self.output){
self.session.addOutput(self.output)
}
self.session.commitConfiguration()
}
catch{
print(error.localizedDescription)
}
}
// take and retake functions...
func takePic(){
self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
DispatchQueue.global(qos: .background).async {
self.session.stopRunning()
DispatchQueue.main.async {
withAnimation{self.isTaken.toggle()}
}
}
}
func reTake(){
DispatchQueue.global(qos: .background).async {
self.session.startRunning()
DispatchQueue.main.async {
withAnimation{self.isTaken.toggle()}
}
}
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
print("reached")
if error != nil{
return
}
guard let imageData = photo.fileDataRepresentation() else{return}
guard let uiImage = UIImage(data: imageData) else {return}
self.image = uiImage
}
}
正如你可以想象的,“reached”只是有时被打印,这就是为什么我的下一个视图有时只包含 UIImage 的原因。我不太确定从这里该做什么。
问题是在照片处理完成之前会话就结束了。它只在某些时候发生,因为我们不知道会话何时结束,因为它是异步发生的。我向其他委托函数添加了调试语句:
func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
print("will begin")
}
func photoOutput(_ output: AVCapturePhotoOutput, didCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
print("did capture")
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {
print("did finish capture")
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
print("did finish processing photo") }
就我而言,我经常只看到“did capture”输出。现在,您可以使用this解决方案来解决此问题,但这不是最佳解决方案。它之所以有效,是因为 stopSession 延迟了足够长的时间以使照片完成处理,但此解决方案不能保证始终有效,甚至可能导致比所需的延迟更长的延迟。更好的解决方案是将
session.stopRunning()
逻辑移至委托函数中,以便您知道它将等到照片处理完毕,并在处理后立即停止会话。现在,您的方法如下所示:
func takePic() {
self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error != nil{
return
}
DispatchQueue.global(qos: .background).async {
self.session.stopRunning()
DispatchQueue.main.async {
withAnimation{self.isTaken.toggle()}
}
}
guard let imageData = photo.fileDataRepresentation() else{return}
guard let uiImage = UIImage(data: imageData) else {return}
self.image = uiImage
}