Swift使用Codable类从Firebase按ID查询文档报错求助
问题描述
我尝试通过文档ID(用户邮箱)从Firebase Firestore查询用户文档,并映射到自定义Codable类Usuario,但一直收到错误:The data couldn’t be read because it is missing.,以下是相关代码和信息,求排查解决。
Firebase数据库结构
集合Usuarios下的文档ID为用户邮箱,文档包含字段:nombre、apellidos、telefono、contraseña、fotoPerfil(可选)、ciudad
Usuario类代码
import Foundation import FirebaseFirestoreSwift class Usuario: Codable { @DocumentID var email: String? let nombre: String let apellidos: String let telefono: String let contraseña: String let fotoPerfil: String? let ciudad: String init ( nombre: String, apellidos: String, usuario: String, contraseña: String, fotoPerfil: String?, ciudad: String){ self.nombre = nombre self.apellidos = apellidos self.telefono = usuario self.contraseña = contraseña self.fotoPerfil = nil self.ciudad = ciudad } }
查询函数代码
private func buscarUsuarioPorEmail( documentId: String) { let docRef = db.collection("Usuarios").document("lorenzorubiorivera@hotmail.com") print("This is a quick check for debugging: \(documentId)") docRef.getDocument(as: Usuario.self) { result in switch result { case .success(let usuario): self.usuarioActual = usuario print("El usuario actual es: \(self.usuarioActual.nombre) ") print(result) case .failure(let error): print("ERROR ENCONTRADO USUARIO \(error.localizedDescription)") } } }
主视图控制器代码
import UIKit import FirebaseAuth import FirebaseCore import FirebaseAnalytics import FirebaseFirestore import Lottie class InicioViewController: UIViewController { // He utilizado una variable tipo lazy para poder inicializarla más tarde cuando se llama a la base datos lazy var usuarioActual = Usuario() lazy var usersCollection = Firestore.firestore().collection("Usuarios") @IBOutlet weak var txtEmailUsuario: UITextView! // Creamos una conexión a Firestore private let db = Firestore.firestore() lazy var collectioRef = db.collection("Usuarios") // MARK: -- Recupero el email mediante su clave en UserDefaults private let email = UserDefaults.standard.string(forKey: "emailAutentificado") override func viewDidLoad() { super.viewDidLoad() title = "Datos usuario actual" txtEmailUsuario.text = email buscarUsuarioPorEmail(documentId: email!) }
控制台输出
This is a quick check for debugging: lorenzorubiorivera@hotmail.com ERROR ENCONTRADO USUARIO The data couldn’t be read because it is missing.
问题排查与修复
1. 初始化器参数不匹配且硬设可选字段值
Usuario的初始化器参数usuario被错误赋值给telefono,同时硬把fotoPerfil设为nil,如果Firestore文档中存在fotoPerfil字段,会导致解码时字段不匹配;且参数名和类属性名对应混乱,影响Codable解析。
修复后的初始化器:
init(nombre: String, apellidos: String, telefono: String, contraseña: String, fotoPerfil: String?, ciudad: String) { self.nombre = nombre self.apellidos = apellidos self.telefono = telefono self.contraseña = contraseña self.fotoPerfil = fotoPerfil // 使用传入的参数,而非硬设为nil self.ciudad = ciudad }
2. 查询函数硬编码文档ID
buscarUsuarioPorEmail中直接写死文档ID,未使用传入的documentId参数,导致无法动态查询目标用户,甚至如果硬编码的文档不存在就会触发错误。
修复后的查询函数:
private func buscarUsuarioPorEmail(documentId: String) { let docRef = db.collection("Usuarios").document(documentId) // 使用传入的documentId参数 print("This is a quick check for debugging: \(documentId)") docRef.getDocument(as: Usuario.self) { result in switch result { case .success(let usuario): self.usuarioActual = usuario print("El usuario actual es: \(usuario.nombre) ") case .failure(let error): print("ERROR ENCONTRADO USUARIO \(error.localizedDescription)") // 额外调试:检查文档是否存在 docRef.getDocument { snapshot, err in if let err = err { print("获取文档快照失败:\(err)") } else if snapshot?.exists == false { print("文档不存在:\(documentId)") } } } } }
3. usuarioActual初始化错误
lazy var usuarioActual = Usuario()会尝试调用默认初始化器,但Usuario没有默认初始化逻辑(所有非可选属性无默认值),会导致编译或运行时异常。
修复后的变量声明:
var usuarioActual: Usuario? // 声明为可选类型,避免提前初始化
4. 验证字段一致性与权限
- 确保Firestore文档中的字段名与
Usuario类的属性名完全一致(大小写敏感),所有非可选字段(如nombre、telefono等)在文档中必须存在且非空; - 检查Firestore安全规则,确认当前用户有权限读取
Usuarios集合下的文档,若规则限制未认证用户读取,需确保用户已登录。
内容的提问来源于stack exchange,提问作者Monrac
相关产品推荐
相关产品推荐

