You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI拍照转base64上传服务端偶发缺失base64字符串问题求助

问题根源

你遇到的偶发base64为空的问题是拍照时序异步逻辑错误导致的:
takePic方法中调用output.capturePhoto是异步操作,系统处理完拍照会走photoOutput回调返回图片数据,但你在触发拍照之后立刻调用了session.stopRunning()终止了相机会话,若回调还没执行会话就被停掉,就会拿不到图片数据,picData始终是初始化的空Data,后续编码出来的base64自然为空。运行结果时好时坏完全取决于回调和停会话的执行顺序,属于典型的竞态问题。

修复方案

1. 调整拍照逻辑时序

把停止会话、更新拍照状态的逻辑移到photoOutput回调中,确保拿到图片数据后再执行后续操作:

func takePic(){
    DispatchQueue.global(qos: .background).async {
        self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
        print("pic taken trigger...")
    }
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    if let error = error {
        print("拍照失败:\(error.localizedDescription)")
        // 拍照失败重启会话避免卡住
        DispatchQueue.global(qos: .background).async {
            self.session.startRunning()
        }
        return
    }
    
    guard let imageData = photo.fileDataRepresentation() else {
        print("获取图片数据失败")
        DispatchQueue.global(qos: .background).async {
            self.session.startRunning()
        }
        return
    }
    // @Published属性必须在主线程更新
    DispatchQueue.main.async {
        self.picData = imageData
        // 拿到数据后再停止会话、更新拍照状态
        DispatchQueue.global(qos: .background).async {
            self.session.stopRunning()
            DispatchQueue.main.async {
                withAnimation{self.isTaken.toggle()}
            }
        }
    }
}

2. 添加上传前置校验

在sendPicData中增加空数据判断,避免发送无效请求:

func sendPicData(){
    guard !picData.isEmpty else {
        print("图片数据为空,无法上传")
        return
    }
    // 原有上传逻辑保持不变
    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)
    }
}

额外优化建议

  • 相机会话的启停、配置操作都建议放到专属串行队列执行,避免多线程调用导致的崩溃
  • 上传前可以判断base64字符串长度,避免发送空字符串
  • 增加用户提示,拍照失败、上传失败时告知用户具体原因

内容的提问来源于stack exchange,提问作者Lloyd English

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 18:00:00