【发布时间】:2017-11-10 11:50:45
【问题描述】:
我正在尝试使用 Swift 4 中的新 JSONDecoder/Encoder 找到对符合 swift 协议的结构数组进行编码/解码的最佳方法。
我编了一个小例子来说明问题:
首先我们有一个协议标签和一些符合这个协议的类型。
protocol Tag: Codable {
var type: String { get }
var value: String { get }
}
struct AuthorTag: Tag {
let type = "author"
let value: String
}
struct GenreTag: Tag {
let type = "genre"
let value: String
}
然后我们有一个类型文章,它有一个标签数组。
struct Article: Codable {
let tags: [Tag]
let title: String
}
最后我们对文章进行编码或解码
let article = Article(tags: [AuthorTag(value: "Author Tag Value"), GenreTag(value:"Genre Tag Value")], title: "Article Title")
let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(article)
let jsonString = String(data: jsonData, encoding: .utf8)
这是我喜欢的 JSON 结构。
{
"title": "Article Title",
"tags": [
{
"type": "author",
"value": "Author Tag Value"
},
{
"type": "genre",
"value": "Genre Tag Value"
}
]
}
问题是在某些时候我必须打开 type 属性来解码数组,但要解码数组我必须知道它的类型。
编辑:
我很清楚为什么 Decodable 不能开箱即用,但至少 Encodable 应该可以工作。以下修改后的 Article 结构编译但崩溃并显示以下错误消息。
fatal error: Array<Tag> does not conform to Encodable because Tag does not conform to Encodable.: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.43/src/swift/stdlib/public/core/Codable.swift, line 3280
struct Article: Encodable {
let tags: [Tag]
let title: String
enum CodingKeys: String, CodingKey {
case tags
case title
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(tags, forKey: .tags)
try container.encode(title, forKey: .title)
}
}
let article = Article(tags: [AuthorTag(value: "Author Tag"), GenreTag(value:"A Genre Tag")], title: "A Title")
let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(article)
let jsonString = String(data: jsonData, encoding: .utf8)
这是 Codeable.swift 中的相关部分
guard Element.self is Encodable.Type else {
preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Element.self) does not conform to Encodable.")
}
来源:https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift
【问题讨论】:
-
为什么要将
AuthorTag和GenreTag分开类型?它们都具有完全相同的界面,而且您似乎只是在使用type属性来区分它们(尽管实际上应该是enum)。 -
这只是一个简化的例子。他们可以有单独的属性。我也想过将 type 设为 enum,但如果 type 是 enum,我无法在不修改 enum 的情况下添加新类型。
-
代码是否实际工作并生成您包含的 JSON?我得到了
Type 'Article' does not conform to protocol 'Decodable'和'Encodable' -
@ThatlazyiOSGuy웃 我看不出这是个错误——
Tag不符合Codable(因此也不符合[Tag]),因为 protocols don't conform to themselves。考虑一下Tag是否符合Codable——解码器尝试解码为任意Tag时会发生什么?应该创建什么具体类型? -
@Hamish 如果是这样,编译器不应允许协议符合可编码
标签: json swift encoding swift4 codable