这实际上与这篇文章AVCapturePhotoCaptureDelegate photoOutput() 不是每次都调用但没有人回应的问题相同。我发现在 takePic 上有时会调用 photoOutput 函数,而不是其他函数,它实际上是 50/50 。我正在使用 Swiftui 2.0 。有谁知道解决这个问题或为什么会发生这个问题?复制它的代码实际上很小。它是下面的代码,然后在info.plist 中设置隐私-相机使用说明和隐私-照片库使用说明的权限。我尝试了不同的方法,但实际上是否调用 photoOutput 仍然是 50/50。当它未被调用时,您将在日志中看到它print("Nil on SavePic:picData")任何建议都会很棒。
import SwiftUI
import AVFoundation
struct CreateStoryView: View {
@StateObject var camera = CameraModel()
@Environment(\.presentationMode) var presentationMode
var body: some View {
ZStack {
// Going to be Camera Preview
CameraPreview(camera: camera)
.ignoresSafeArea(.all, edges: .all)
VStack {
HStack {
Spacer()
Image(systemName: "arrowshape.turn.up.backward.circle.fill")
.foregroundColor(.black)
.padding(.trailing,20)
.background(Color.white)
.clipShape(/*@START_MENU_TOKEN@*/Circle()/*@END_MENU_TOKEN@*/)
.onTapGesture {
if camera.session.isRunning == true {
camera.session.stopRunning()
}
self.presentationMode.wrappedValue.dismiss()
}
if camera.isTaken {
Button(action: camera.reTake, label: { // camera.reTake
Image(systemName: "arrow.triangle.2.circlepath.camera")
.foregroundColor(.black)
.padding()
.background(Color.white)
.clipShape(/*@START_MENU_TOKEN@*/Circle()/*@END_MENU_TOKEN@*/)
})
.padding(.trailing,10)
}
}
Spacer()
HStack{
// If Taken then showing save and again take button
if camera.isTaken{
Button(action: {if !camera.isSaved{camera.savePic()}}, label: {
Text(camera.isSaved ? "Saved" : "Save")
.foregroundColor(.black)
.fontWeight(.semibold)
.padding(.vertical,10)
.padding(.horizontal,20)
.background(Color.white)
.clipShape(Capsule())
})
.padding(.leading)
Spacer()
} else {
Button(action: camera.takePic , label: {
ZStack{
Circle()
.fill(Color.white)
.frame(width: 65, height: 65)
Circle()
.stroke(Color.white,lineWidth: 2)
.frame(width: 75, height: 75)
}
})
}
}.frame(height: 75)
}
}.onAppear(perform: {
camera.Check()
})
}
}
// Camera Model
class CameraModel: NSObject,ObservableObject,AVCapturePhotoCaptureDelegate {
@Published var isTaken = false
@Published var session = AVCaptureSession()
@Published var alert = false
@Published var output = AVCapturePhotoOutput()
// preview ...
@Published var preview: AVCaptureVideoPreviewLayer!
@Published var isSaved = false
@Published var picData = Data(count: 0)
func Check() {
// first checking camera has permission
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
setUp()
return
case .notDetermined:
//retrusting 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(.builtInDualCamera,for: .video,position: .back)
let input = try AVCaptureDeviceInput(device: device!)
// checking and adding 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
func takePic(){
DispatchQueue.global(qos: .background).async {
self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
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() }
// clearing
//self.isSaved = false
self.isTaken = false
}
}
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
print("photoOutput check")
if error != nil {
return
}
guard var imageData = photo.fileDataRepresentation() else {return}
self.picData = imageData
if isSaved == true {
if !imageData.isEmpty {
imageData.removeAll()
isSaved = false
}
} else {
isSaved = true
}
}
func savePic() {
if UIImage(data: self.picData) == nil {
print("Nil on SavePic:picData")
return
}
let image = UIImage(data: self.picData)!
// saving image
UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil)
self.isSaved = true
print("saved sucessfully")
}
@objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
print("Save finished!")
}
}
// setting up view for preview
struct CameraPreview: UIViewRepresentable {
@ObservedObject var camera: CameraModel
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.frame
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
struct CreateStoryView_Previews: PreviewProvider {
static var previews: some View {
CreateStoryView()
}
}