Swift Codable 多种类型
Posted
技术标签:
【中文标题】Swift Codable 多种类型【英文标题】:Swift Codable multiple types 【发布时间】:2019-03-11 21:24:31 【问题描述】:我尝试解析返回 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 的初学者)并且我找不到解决问题的方法。我知道我必须使用自定义初始化,但我不知道如何。
【问题讨论】:
【参考方案1】:你可以试试
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)
【讨论】:
当我尝试访问“value”的值以在 label.text 中使用它时,我收到错误“无法分配类型为 'MyValue?' 的值?”键入“字符串?”。当我将值打印到终端时,它会显示 ... unknown context at 0x109d06188).MyValue.string ... 你知道我该如何解决这个问题吗? @Sylvain 这可能是因为它是枚举,而不是字符串值。 如何从变量值中获取价值?每当我尝试打印值时,它都会显示 MyValue.string("value") MyValue.string("value"),什么是 "Value" ,这正是我们将值传递给枚举的内容,但在此之前我们需要获取该特定值。【参考方案2】:基于@Sh_Khan 的回答并回答 cmets 中@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
【讨论】:
你能告诉我把这段代码放在哪里吗? @gudio 在枚举声明中 非常感谢@guido。现在我可以获取值了。 @guido 如何手动为其设置值,例如 Root.value = 1 ?以上是关于Swift Codable 多种类型的主要内容,如果未能解决你的问题,请参考以下文章
Swift 根据响应类型为 JSON 字段值动态选择 Codable 结构