SwiftUI异步问题:sendImage未完成时handleImageSend提前执行
问题原因
核心问题是异步操作执行顺序错误:ImageUploader.sendImage是异步函数,它的completion回调要等图片上传完成、拿到下载URL后才会触发,但你现在在回调外部就直接使用imageURL——此时回调还未执行,imageURL必然为nil。所有依赖该URL的代码必须放在completion闭包内部,确保拿到URL后再执行后续逻辑。
修复方案1:调整Completion回调内的代码逻辑
修改handleImageSend函数,将所有需要用到图片URL的代码移到sendImage的completion闭包中:
func handleImageSend(image: UIImage?) { guard let fromId = FirebaseManager.shared.auth.currentUser?.uid else { return } guard let chatUser = chatUser else { return } guard let image = image else { return } ImageUploader.sendImage(image: image) { url in let document = FirebaseManager.shared.firestore .collection("messages") .document(fromId) .collection(chatUser.uid) .document() print("DEBUG: \(url)") let imageMessageData = ["fromId": fromId, "toId": chatUser.uid, "text": url, "timestamp": Timestamp()] as [String : Any] if !imageMessageData.isEmpty { self.messageIsAnImage.toggle() } document.setData(imageMessageData) { error in if let error = error { print(error.localizedDescription) return } } self.persistRecentMessage() let recipientDocument = FirebaseManager.shared.firestore .collection("messages") .document(chatUser.uid) .collection(fromId) .document() recipientDocument.setData(imageMessageData) { error in if let error = error { print(error.localizedDescription) return } } } }
修复方案2:改用Async/Await简化代码
如果你想用async/await,先把ImageUploader.sendImage改成异步函数,避免回调嵌套:
第一步:修改ImageUploader的sendImage函数
struct ImageUploader { // 保留原有uploadImage函数 static func sendImage(image: UIImage) async throws -> String { guard let imageData = image.jpegData(compressionQuality: 0.5) else { throw NSError(domain: "ImageUploadError", code: 0, userInfo: [NSLocalizedDescriptionKey: "无法将图片转为数据"]) } let ref = FirebaseManager.shared.storage.reference(withPath: UUID().uuidString) try await ref.putData(imageData) let url = try await ref.downloadURL() return url.absoluteString } }
第二步:修改handleImageSend为异步函数
func handleImageSend(image: UIImage?) async { guard let fromId = FirebaseManager.shared.auth.currentUser?.uid else { return } guard let chatUser = chatUser else { return } guard let image = image else { return } do { let url = try await ImageUploader.sendImage(image: image) let document = FirebaseManager.shared.firestore .collection("messages") .document(fromId) .collection(chatUser.uid) .document() print("DEBUG: \(url)") let imageMessageData = ["fromId": fromId, "toId": chatUser.uid, "text": url, "timestamp": Timestamp()] as [String : Any] if !imageMessageData.isEmpty { messageIsAnImage.toggle() } try await document.setData(imageMessageData) persistRecentMessage() let recipientDocument = FirebaseManager.shared.firestore .collection("messages") .document(chatUser.uid) .collection(fromId) .document() try await recipientDocument.setData(imageMessageData) } catch { print("图片上传或消息存储失败:\(error.localizedDescription)") } }
调用时需在异步上下文执行(比如SwiftUI视图中用Task):
// 视图内调用示例 Button("发送图片") { if let image = selectedImage { Task { await viewModel.handleImageSend(image: image) } } }
内容的提问来源于stack exchange,提问作者Grant
相关产品推荐
相关产品推荐

