使用可编码和Firestore的不对称编码/解码



我有以下结构:

struct Recipe: Codable {
@DocumentID var id: String?
var vegetarian: Bool?

private enum CodingKeys: String, CodingKey {
case id
case vegetarian
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
vegetarian = try container.decode(Bool.self, forKey: .vegetarian)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(vegetarian, forKey: .vegetarian)
}
}

我正在尝试:

  • 仅解码vegetarian
  • 编码vegetarianid

这是我的数据模型:

docRef.getDocument { document, error in
if let error = error as NSError? {
self.errorMessage = "Error getting document: (error.localizedDescription)"
}
else {
if let document = document {
do {
self.recipe = try document.data(as: Recipe.self)

let recipeFromFirestore = Recipe(
id: self.recipe!.id,
vegetarian: self.recipe!.vegetarian)

self.recipes.append(recipeFromFirestore)
}
catch {
print("Error: (error)")
}
}
}
}

我的getDocument:Missing argument for parameter 'from' in call中出现以下错误。

如果我在结构中注释掉init(from decoder: Decoder)func encode(to encoder: Encoder),则不会发生此错误。我应该为这种不对称编码/解码做一些不同的事情吗?

我不知道你从哪里看到这个错误-行引用会很有用-但它与你的en/解码没有直接关系。(顺便说一句,这种方法实际上不是一个数据模型(

由于您希望使用与属性名称匹配的JSON密钥来解码这两个属性,因此无需指定CodingKeys或编写自定义解码器;你可以依靠合成解码器,让Codable为你做这项工作。

对于解码,您将需要一个自定义解决方案,否则Decodable将对两个字段进行解码。这将需要CodingKey枚举(注意单数,即协议,而不是缺省枚举名称(和自定义编码器来使用它。

您最终得到的结构实现要简单得多。我还添加了一个简单的初始化器,因为一旦定义了init(from:),就会丢失合成的成员初始化器。这只是为了让我可以测试一下。

struct Recipe: Codable {
var id: String?
var vegetarian: Bool?

init(id: String, vegetarian: Bool){
self.id = id
self.vegetarian = vegetarian
}

init(from decoder: Decoder) throws {

enum DecodingKeys: CodingKey {
case vegetarian
}

let container = try decoder.container(keyedBy: DecodingKeys.self)
vegetarian = try container.decode(Bool.self, forKey: .vegetarian)
}
}

如果你测试它,你会发现它只会解码vegetarian属性,但会对两者进行编码。简单测试显示:

let recipe = Recipe(id: "1", vegetarian: true)
let data = try! JSONEncoder().encode(recipe)
print(String(data: data, encoding: .utf8)!)  //{"id":"1","vegetarian":true}
let decodedRecipe = try! JSONDecoder().decode(Recipe.self, from: data)
print(decodedRecipe) //Recipe(id: nil, vegetarian: Optional(true))

最新更新