你好Codable
专家。
我想解码艺术家数据的传入JSON。存在两种类型的艺术家:个人和乐队。
个人代表如下:
{
"id":"123",
"data":{
"type":"individual",
"firstName":"David",
"lastName":"Bowie"
}
}
而乐队代表这样:
{
"id":"124",
"data":{
"type":"band",
"name":"Queen"
}
}
我正在尝试在Swift中对此JSON polymorphism建模(🤔不确定这是正确的词),如下所示:
import Foundation
struct Artist: Decodable {
let id: String
let data: ArtistData
}
enum ArtistType: String, Codable {
case individual
case band
}
protocol ArtistData: Decodable {
var type: ArtistType { get }
}
struct IndividualArtistData: ArtistData, Codable {
let type = ArtistType.individual
let firstName: String
let lastName: String
}
struct BandArtistData: ArtistData, Codable {
let type = ArtistType.band
let name: String
}
但是出现以下错误:
Type 'Artist' does not conform to protocol 'Decodable'
cannot automatically synthesize 'Decodable' because 'ArtistData' does not conform to 'Decodable'
[我还尝试了一个版本,其中ArtistData
协议不继承Decodable
并更改Artist
定义以使用协议组成,如下所示:
struct Artist: Decodable {
let id: String
let data: ArtistData & Decodable
}
但出现类似错误:
cannot automatically synthesize 'Decodable' because 'Decodable & ArtistData' does not conform to 'Decodable'
我应该如何处理这种情况?
节日快乐。🌲🎅
data
中的[Artist
必须是具体类型或限于Codable
的泛型。它不能是协议。
我的建议是删除协议,并声明一个具有关联类型的枚举。
enum Artist : Decodable {
case individual(String, IndividualArtist), band(String, BandArtist)
private enum CodingKeys : String, CodingKey { case id, data }
private enum ArtistKeys : String, CodingKey { case type }
init(from decoder : Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(String.self, forKey: .id)
let nestedContainer = try container.nestedContainer(keyedBy: ArtistKeys.self, forKey: .data)
let type = try nestedContainer.decode(ArtistType.self, forKey: .type)
switch type {
case .individual:
let individualData = try container.decode(IndividualArtist.self, forKey: .data)
self = .individual(id, individualData)
case .band:
let bandData = try container.decode(BandArtist.self, forKey: .data)
self = .band(id, bandData)
}
}
}
enum ArtistType : String, Decodable {
case individual
case band
}
struct IndividualArtist : Decodable {
let type : ArtistType
let firstName: String
let lastName: String
}
struct BandArtist : Decodable {
let type : ArtistType
let name: String
}