Swift用Firestore.Encoder编码Codable报FIRInvalidArgumentException
报错根因
FIRInvalidArgumentException触发的核心原因是你传入了Firestore不支持的数据类型,你的代码里有两个明确的问题:
- 你用
try?静默吞掉了编码阶段的所有错误,无法直接定位具体异常点。绝大多数同类场景下,是因为Swift原生的可选类型nil(即Optional<T>.none)没有被正确转换为Firestore识别的NSNull,被直接塞入写入字典后触发类型校验失败。 - 代码中对
serialNum做了强制解包serialNum!,如果入参serialNum为nil会直接触发通用崩溃;另外如果serialNum包含斜杠、点号等Firestore文档ID禁止的特殊字符、或为空字符串,也会抛出同名非法参数异常。
修复步骤
- 替换
try?写法,用do-catch捕获抛出的具体错误,先定位异常字段:
do { let encodeResult = try Firestore.Encoder().encode(device) print("编码结果:\(encodeResult)") } catch { print("编码错误详情:\(error)") }
- 配置编码器的nil值处理策略,从根源避免非法类型传入:
let encoder = Firestore.Encoder() // 编码时自动忽略值为nil的字段,不生成对应的键值对,避免写入非法的Optional.none encoder.nilEncodingStrategy = .omit
- 移除强制解包,在写入前校验所有路径参数合法性:
// Firestore文档ID要求:非空、不包含/和.、长度不超过1500字节 guard let serialNum = serialNum, !serialNum.isEmpty, !serialNum.contains("/"), !serialNum.contains("."), serialNum.utf8.count <= 1500, !email.isEmpty, !email.contains("/") else { print("路径参数不符合Firestore要求,终止写入") return }
- 最简写法优化:导入
FirebaseFirestoreSwift模块后,不需要手动调用编码器,直接使用setData(from:)方法写入Codable结构体,SDK会自动处理类型兼容问题:
public struct Device: Codable { let name: String? let address: String? let serialNum: String? let email: String? let password: String? } func bindDeviceToUser(name: String?, email: String, devicePassword: String?, serialNum: String?, address: String?) { // 先校验路径参数 guard !email.isEmpty, !email.contains("/"), let serialNum = serialNum, !serialNum.isEmpty, !serialNum.contains("/"), !serialNum.contains(".") else { return } let device = Device(name: name, address: address, serialNum: serialNum, email: email, password: devicePassword) let targetDoc = firestore.collection("Users").document(email).collection("Devices").document(serialNum) do { // 直接写入包含Codable对象的字典,SDK自动完成编码 try targetDoc.setData(from: ["Data": device]) } catch { print("写入失败:\(error)") } }
内容的提问来源于stack exchange,提问作者Dylon Jaynes
相关产品推荐
相关产品推荐

