Еще одно объяснение:
Поскольку здесь не так много объяснений, вот еще один пример того, что объяснил @vadian:
1. В Swift использует enum вместо struct для достижения «гибкого типа».
2. Затем вам понадобятся парсеры для «элемента» и для «типа».
2. Разбор, а затем просто переключитесь на декодирование и установите правильный тип.
Так что для JSON выше, у вас будет
struct YourFeed: Decodable {
let stuff: [Item]
}
Каждый элемент может быть автомобилем или домом.
struct Car: Decodable { ... }
struct House: Decodable { ... }
Так что все просто.
Теперь для Item
. Это может быть несколько типов.
В Swift используйте enum вместо struct для достижения «гибкого типа».
// in Swift, an "enum" is basically a "struct" which can have a flexible type,
// so here we have enum Item rather than struct Item:
enum Item: Decodable {
// so this thing, Item, can be one of these two types:
case car(Car)
case house(House)
Далее просто отразите это внеобработанное перечисление, которое будет использоваться для анализа поля типа. (Вы можете назвать это как угодно, я только что назвал это "Parse".)
// the relevant key strings for parsing the "type" field:
private enum Parse: String, Decodable {
case car
case house
}
Далее, посмотрите на исходный JSON сверху. Каждый «элемент» имеет два поля: «тип» и «объект». Вот они в сыром перечислении. (Опять же, вы можете называть это как угодно, я только что назвал это «Ключами».)
// we're decoding an item, what are the top-level tags in item?
private enum Keys: String, CodingKey {
// so, these are just the two fields in item from the json
case type
case object
}
Имеем перечисление для анализа уровня элемента и перечисление для анализа типа.
Наконец, напишите инициализатор для "Item". Просто декодируйте верхний уровень и «тип» ...
init(from decoder: Decoder) throws {
// parse the top level
let c = try decoder.container(keyedBy: Keys.self)
// and parse the 'type' field
let t = try c.decode(Parse.self, forKey: .type)
... и все готово. Декодируйте данные (используя соответствующий класс) и установите для объекта перечисления «Item» соответствующий тип.
Выполните синтаксический анализ, а затем просто переключитесь на декодирование / установку перечисления.
// we're done, so depending on which of the types it is,
// decode (using the relevant decoder), and become the relevant type:
switch t {
case .car:
let d = try c.decode(Car.self, forKey: .object)
self = .car(d)
case .house:
let d = try c.decode(House.self, forKey: .object)
self = .house(d)
}
}
}
Вот и всё за один раз:
enum Item: Decodable {
case car(Car)
case house(House)
// the relevant key strings for parsing the 'type' field:
private enum Parse: String, Decodable {
case car
case house
}
// the top-level tags in 'item':
private enum Keys: String, CodingKey {
case type
case object
}
init(from decoder: Decoder) throws {
// parse the top level
let c = try decoder.container(keyedBy: Keys.self)
// parse the 'type' field
let t = try c.decode(Parse.self, forKey: .type)
// we're done, switch to
// decode (using the relevant decoder), and become the relevant type:
switch t {
case .car:
let d = try c.decode(Car.self, forKey: .object)
self = .car(d)
case .house:
let d = try c.decode(House.self, forKey: .object)
self = .house(d)
}
}
}