如果某些东西符合 Codable ,它会永远无法被编码或解码吗?
Posted
技术标签:
【中文标题】如果某些东西符合 Codable ,它会永远无法被编码或解码吗?【英文标题】:If something conforms to Codable can it EVER fail to be Encoded or Decoded? 【发布时间】:2021-07-16 15:15:53 【问题描述】:我想知道符合Codable
的对象在编码或解码过程中是否会导致错误。我觉得好像符合协议确保永远不会抛出错误。
例如,如果我有一个名为 Book
的 struct
:
struct Book: Codable, Identifiable
@DocumentID var id: String?
var name: String
这个struct
永远会不会被编码或解码失败?
例如,如果我这样做:
try! docRef.setData(from: book) error in _
如果Book
符合Codable
,我认为这永远不会同步抛出错误。
同样,
try! docRef.data(as: Book.self)
应该从不抛出,因为Book
再次符合Codable
如果我错了,Book
在编码或解码时可能会失败,请说明在什么条件/情况下可能会发生。
提前致谢!
【问题讨论】:
如果您拥有并控制自定义类型和数据源,那么一旦经过正确测试,它就永远不会失败。 @JoakimDanielson 正确测试是什么意思?我确实控制了“将数据放入 Firestore”以及“从 Firestore 中检索数据”这两个方面。当我编码和上传数据然后下载和解码数据时,它工作得很好。这是否意味着它已经过正确测试? 通过适当的测试,我相信 Joakin 意味着它理论上应该可以工作并且永远不会失败。只要您有足够的控制来确保数据准确且格式正确。单元测试将有助于确保这一点 @Scriptable 非常感谢您的回答。我已经为这件事烦恼了两天了。超级超级感谢:D 是的,经过适当测试,我的意思是在开发阶段之后进行测试,以便编码/解码按预期工作。 【参考方案1】:正如您在 Firestore 的背景下提出的这个问题,除了 Ralf 在他的回答中提到的内容之外,我想添加更多细节。
在解码 Firestore 文档时,有许多情况可能会导致映射错误,这就是您应该准备好处理它们的原因。
例如:
您的结构可能需要一个字段(即它是非可选的),但 Firestore 文档中缺少该字段。当您有其他应用(android、Web 甚至您的 ios 应用的早期版本)写入同一文档但使用早期版本的架构时,可能会发生这种情况 文档中的一个(或多个)属性的数据类型可能与您的结构不同。以下代码 sn-p 包含针对这些情况和其他情况的大量错误处理(请注意,您需要根据个人情况调整处理这些错误的方式 - 您可能希望也可能不希望显示用户可见的错误消息,例如)。代码摘自我的文章Mapping Firestore Data in Swift - The Comprehensive Guide。
class MappingSimpleTypesViewModel: ObservableObject
@Published var book: Book = .empty
@Published var errorMessage: String?
private var db = Firestore.firestore()
func fetchAndMap()
fetchBook(documentId: "hitchhiker")
func fetchAndMapNonExisting()
fetchBook(documentId: "does-not-exist")
func fetchAndTryMappingInvalidData()
fetchBook(documentId: "invalid-data")
private func fetchBook(documentId: String)
let docRef = db.collection("books").document(documentId)
docRef.getDocument document, error in
if let error = error as NSError?
self.errorMessage = "Error getting document: \(error.localizedDescription)"
else
let result = Result try document?.data(as: Book.self)
switch result
case .success(let book):
if let book = book
// A Book value was successfully initialized from the DocumentSnapshot.
self.book = book
self.errorMessage = nil
else
// A nil value was successfully initialized from the DocumentSnapshot,
// or the DocumentSnapshot was nil.
self.errorMessage = "Document doesn't exist."
case .failure(let error):
// A Book value could not be initialized from the DocumentSnapshot.
switch error
case DecodingError.typeMismatch(let type, let context):
self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
case DecodingError.valueNotFound(let type, let context):
self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
case DecodingError.keyNotFound(let key, let context):
self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
case DecodingError.dataCorrupted(let key):
self.errorMessage = "\(error.localizedDescription): \(key)"
default:
self.errorMessage = "Error decoding document: \(error.localizedDescription)"
如果您对 Firestore 如何实现 Codable 协议感到好奇,请访问source code。例如,搜索 DecodableError
将显示哪些错误情况可能发生的确切程度以及原因。
【讨论】:
谢谢.. 我的映射失败了,我不明白为什么。属性中的拼写错误。谢谢!【参考方案2】:编码:
对于 JSONEncoder,此处记录了编码失败的情况:https://developer.apple.com/documentation/foundation/jsonencoder/2895034-encode。 Afaik 假设所有属性和包含的数据结构都由简单的类型组成,如 Int、String、Array、Dictionary,它永远不会失败,因为这些值总是可以表示为 JSON。但是你可能有一个像 Float 这样的类型,当值不能表示为 JSON 时,它会抛出一个错误。
解码:
任何无效的 JSON 输入(例如缺少字段或语法错误)都会引发错误。我建议始终处理这些问题并确保它们不会被忽视/用户至少会获得“抱歉,出了点问题,我们正在调查”的体验。
【讨论】:
您是否建议也对book.id ?? ""
之类的东西使用 nil 合并?或者对@DocumentID
属性使用强制解包很好?即book.id!
以上是关于如果某些东西符合 Codable ,它会永远无法被编码或解码吗?的主要内容,如果未能解决你的问题,请参考以下文章
符合 Codable 协议的类因 encodeWithCoder 失败:无法识别的选择器发送到实例