Home > OS >  SwiftUI- server not receiving base64 string
SwiftUI- server not receiving base64 string

Time:09-18

What I'm trying to do is take a picture, encode it to base64 and then send it in a dictionary to my server. When I send the dictionary over, sometimes it sends with the base64 and sometimes it sends without it even if I don't make any changes. Here's the code for the camera view

struct CameraView: View {

@StateObject var camera = CameraModel()

var body: some View {
    ZStack {
        CameraPreview(camera: camera)
            .ignoresSafeArea(.all, edges: .all)
        
        VStack{
            if camera.isTaken{
                
                HStack {
                    
                    Spacer()
                    
                    Button(action: camera.retake, label: {
                        Image(systemName: "arrow.triangle.2.circlepath.camera")
                            .foregroundColor(.black)
                            .padding()
                            .background(Color.white)
                            .clipShape(Circle())
                    })
                    .padding(.trailing, 10)
                }
            }
    
            Spacer()
            
            HStack{
                if camera.isTaken{
                    Button(action: camera.sendPicData , label: {
                        Text("Save")
                            .foregroundColor(.black)
                            .fontWeight(.semibold)
                            .padding(.vertical, 10)
                            .padding(.horizontal, 10)
                            .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()
    })
}
}

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) {
    
}
}

and the code for taking the picture and sending it to server

class CameraModel: NSObject, ObservableObject, AVCapturePhotoCaptureDelegate{
@Published var isTaken = false
@Published var alert = false
@Published var sendPic = false
@Published var session = AVCaptureSession()
@Published var output = AVCapturePhotoOutput()
@Published var preview: AVCaptureVideoPreviewLayer!
@Published var picData = Data(count: 0)

func Check(){
    switch AVCaptureDevice.authorizationStatus(for: .video) {
    case .authorized:
        setUp()
        return
    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .video) { (status) in
            if status{
                self.setUp()
            }
        }
    case .denied:
        self.alert.toggle()
        return
    default:
        return
    }
}

func setUp(){
    do{
        self.session.beginConfiguration()
        
        let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
        let input = try AVCaptureDeviceInput(device: device!)
        
        if self.session.canAddInput(input){
            self.session.addInput(input)
        }
        
        if self.session.canAddOutput(self.output){
            self.session.addOutput(self.output)
        }
        self.session.commitConfiguration()
    }
    catch{
        print(error.localizedDescription)
    }
}

func takePic(){
    DispatchQueue.global(qos: .background).async {
        self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
        self.session.stopRunning()
        
        DispatchQueue.main.async {
            withAnimation{self.isTaken.toggle()}
        }
        print("pic taken...")
    }
}

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?) {
    if error != nil{
        return
    }
    
    guard let imageData = photo.fileDataRepresentation() else{return}
    self.picData = imageData
}

func sendPicData(){
    let image = UIImage(data: self.picData)
    let imageData: Data = image?.jpegData(compressionQuality: 0.1) ?? Data()
    let imageString: String = imageData.base64EncodedString()
            
    let dictionary:[String:String] = ["Dot":imageString]
    if let theJSONData = try? JSONSerialization.data(withJSONObject: dictionary, options: [.prettyPrinted]) {

        guard let sendURL = URL(string:"http://toServer") else {
            print("invalid URL")
            return
        }
        var request = URLRequest(url: sendURL)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.httpMethod = "POST"
        request.httpBody = theJSONData

        URLSession.shared.dataTask(with: request) {data, response, error in
            guard data != nil else {
                print ("PUT Failed: \(error?.localizedDescription ?? "Unknown Error")")
                return
            }
        }.resume()

        print(dictionary)
    }
}
}

I don't know why it's so inconsistent. It doesn't make any sense to me, if it works once why wouldn't it work every time? Help Please

CodePudding user response:

The problem was that the delegate function func photoOutput() wasn't being called every time the picture was taken. I found that in func takePic(), if I put a Timer on self.session.stopRunning() it would fix the problem and call the delegate function every time but it would also cause another problem that would stop calling on self.isTaken.toggle(). To fix that I put the Timer in a DispatchQueue.main.async like so

func takePic(){
    DispatchQueue.global(qos: .background).async {
        self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
        DispatchQueue.main.async {
            Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
                self.session.stopRunning()
            }
        }
        
        DispatchQueue.main.async {
            withAnimation{self.isTaken.toggle()}
        }
        print("pic taken...")
    }
}

I'm not sure if this is the best way to solve this but I've seen a lot of other people with the same similar problem and with this solution it will call the delegate function every time.

  • Related