我有以下结构:
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
- 编码
vegetarian
和id
这是我的数据模型:
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))