Jsonオブジェクトを返すapiを解析しようとしています。私の問題は、一部のキーが文字列である場合と、次の例の「Value」キーのようなオブジェクトである場合があります。
[
{
"Description": null,
"Group": "Beskrivning av enheten",
"GroupDescription": null,
"Id": "Description",
"Name": "Mer om enheten",
"Value": "Det finns möjlighet till parkering på gatorna runt om, men det är kantstenar och ganska branta backar för att komma upp till lekplatsen.\r\n\r\nUtanför själva lekplatsen finns en gungställning med en plan omväg in. Alla lekredskap står i sandytor, det finns många kanter. Runt hela lekplatsen går ett staket med öppningar i olika riktningar."
},
{
"Description": null,
"Group": "Bilder och film",
"GroupDescription": null,
"Id": "Image",
"Name": "Huvudbild",
"Value": {
"__type": "FileInfo",
"Id": "8871b3b1-14f4-4054-8728-636d9da21ace",
"Name": "ullerudsbacken.jpg"
}
}
]
私の構造体は次のようになります:
struct ServiceUnit: Codable {
let description: String?
let group: String?
let groupDescription: String?
let id: String
let name: String
var value: String?
struct ServiceUnitTypeInfo: Codable {
let id: String
let singularName: String?
enum CodingKeys: String, CodingKey {
case id = "Id"
case singularName = "SingularName"
}
}
let serviceUnitTypeInfo: ServiceUnitTypeInfo?
let values: [String]?
enum CodingKeys: String, CodingKey {
case description = "Description"
case group = "Group"
case groupDescription = "GroupDescription"
case id = "Id"
case name = "Name"
case value = "Value"
case serviceUnitTypeInfo = "ServiceUnitTypeInfo"
case values = "Values"
case image = "Image"
}
}
私は完全に迷子になっていることを管理する必要があります(そう、私はSwiftの初心者です)。私の問題の解決策を見つけることができません。カスタムinitを使用する必要があることは理解していますが、方法がわかりません。
あなたが試すことができます
struct Root: Codable {
let description,id: String
let group,groupDescription: String?
let name: String
let value: MyValue
enum CodingKeys: String, CodingKey {
case description = "Description"
case group = "Group"
case groupDescription = "GroupDescription"
case id = "Id"
case name = "Name"
case value = "Value"
}
}
enum MyValue: Codable {
case string(String)
case innerItem(InnerItem)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
if let x = try? container.decode(InnerItem.self) {
self = .innerItem(x)
return
}
throw DecodingError.typeMismatch(MyValue.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let x):
try container.encode(x)
case .innerItem(let x):
try container.encode(x)
}
}
}
struct InnerItem: Codable {
let type, id, name: String
enum CodingKeys: String, CodingKey {
case type = "__type"
case id = "Id"
case name = "Name"
}
}
do {
let result = try JSONDecoder().decode([Root].self,from:data)
print(result)
}
catch {
print(error)
}
@Sh_Khanの回答に基づいて、コメントで@Nikhiの質問に回答するには(値にアクセスするにはどうすればよいですか)これを列挙型宣言に追加します。
var innerItemValue: InnerItem? {
switch self {
case .innerItem(let ii):
return ii
default:
return nil
}
}
var stringValue: String? {
switch self {
case .string(let s):
return s
default:
return nil
}
}