AVCapturePhotoCaptureDelegate photoOutput() 不是每次都调用

问题描述 投票:0回答:1

我正在按照本教程为我的应用程序创建自定义相机。捕获图片后,用户可以继续到显示图像的另一个视图。不幸的是,有时图像根本不显示在下一页上,而其他时候却工作得很好。看来我的委托函数并没有一直被调用:

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 的原因。我不太确定从这里该做什么。

ios swift swiftui avfoundation
1个回答
0
投票

问题是在照片处理完成之前会话就结束了。它只在某些时候发生,因为我们不知道会话何时结束,因为它是异步发生的。我向其他委托函数添加了调试语句:

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
}
© www.soinside.com 2019 - 2024. All rights reserved.