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
相关产品推荐
相关产品推荐

