#ios #json #swift
Вопрос:
Получен ответ Json
{
"data": [
{
"key": "email",
"value": "qfmppddybsfeiiiazh@mrvpt.com"
},
{
"key": "name",
"value": "Tg baa"
},
{
"key": "dob",
"value": "1999-06-06"
},
{
"key": "nationality",
"value": "UK"
},
{
"key": "address",
"value": [
{
"key": "addr1",
"value": "Bundle road, near church 460102"
},
{
"key": "postalCode",
"value": "46HG02"
},
{
"key": "city",
"value": "London"
}
]
}
],
"Greeting": "Birthday",
"Service": "mydelivery"
}
Сгенерированная модель с помощью онлайн-инструмента
// MARK: - Welcome
public struct Welcome: Codable {
public let data: [Datum]
public let Greeting, Service: String
}
// MARK: - Datum
public struct Datum: Codable {
public let key: String
public let value: ValueUnion
}
public enum ValueUnion: Codable {
case string(String)
case valueElementArray([ValueElement])
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode([ValueElement].self) {
self = .valueElementArray(x)
return
}
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
throw DecodingError.typeMismatch(ValueUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ValueUnion"))
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let x):
try container.encode(x)
case .valueElementArray(let x):
try container.encode(x)
}
}
}
// MARK: - ValueElement
public struct ValueElement: Codable {
let key, value: String
}
Попробуйте получить доступ к массиву адресов в модели. но всегда терпит неудачу
print("onboardingStatus: (result?.Greeting ?? "")")
print("idService: (result?.Service ?? "")")
guard let userData = result?.data else { return }
for item in userData {
if item.key == "address" {
guard let address_info = item.value as? [ValueElement] else { return }
for ad in address_info {
print(ad.key)
print(ad.value)
}
}
print(item.key)
print(item.value)
}
Я хочу просмотреть ключ и значения адреса. но я получаю ошибку «Для цикла ввода требуется, чтобы» Объединение значений «соответствовало» Последовательности»». пожалуйста, помогите.
Комментарии:
1. Я скопировал/вставил ваш код, и я получил «Приведение от» Объединения значений «к несвязанному типу» [Элемент значения] «всегда не удается», а не вашу ошибку…
2. да, я хочу привести к [элементу ValueElement], чтобы я мог выполнить цикл.
3. вы должны преобразовать свой ответ JSON в объект модели следующим образом :- пусть decoder = JSONDecoder() сделает { пусть люди = попробуют декодер.декодировать(имя модели.само, от: результат.значение) печать(люди) } поймать { печать(ошибка.локализованное описание) }
4. Вы также можете удалить код рядом со структурой …. начиная с перечисления и до конца
Ответ №1:
Ошибка компилятора, которую вы должны получить на:
guard let address_info = item.value as? [ValueElement] else { return }
является
Cast from 'ValueUnion' to unrelated type '[ValueElement]'
Не «Для цикла» требуется, чтобы «Объединение значений «соответствовало»Последовательности»».
Ошибка явная, address_info
это объединение значений, а не [ValueElement]
. В вашем конкретном случае это почти так, но поскольку это а ValueUnion
, это может быть а String
вместо этого. В конце концов, ValueUnion
это связанное перечисление значений для обработки строки и массива ValueElement
.
Быстрое «исправление» было бы:
if case let .valueElementArray(address_info) = item.value {
for ad in address_info {
print(ad.key)
print(ad.value)
}
}
Но это может быть слишком продвинуто (и бесполезно, если вы этого не понимаете).
switch item.value {
case .string(let aString):
print("Found a string: (aString)")
case .valueElementArray(let elements):
for ad in elements {
print(ad.key)
print(ad.value)
}
}
Теперь ваш JSON странный, и в конце концов вам может понадобиться модель, поэтому либо сделайте «сопоставление» между вашей текущей моделью в эту, либо с некоторой работой (возможно, слишком много работы для результата), декодируйте непосредственно в эту модель.
struct UserOrSomething {
let greeting: String
let service: String
let infos: Infos
}
struct Infos {
let name: String
let dob: String
let email: String
let nationality: String
let address: Address
}
struct Address {
let addr1: String
let addr2: String
let postalCode: String
let city: String
let state: String
let region: String
}
Комментарии:
1. использование пункта включения работает . Спасибо вам за поддержку.
Ответ №2:
Ваше объединение значений может быть одним из двух различных значений, либо одной строкой, либо массивом пар ключ/значение. Вы говорите, что «хотите привести к [элементу значения]», чтобы вы могли перебирать их, но что, если объединение значений не содержит массива элементов значения?
Сначала вы должны выяснить, существует ли массив вообще в объединении значений…
func example(valueUnion: ValueUnion) {
if case let .valueElementArray(array) = valueUnion {
for each in array {
print("valueElement - key:", each.key, " value:", each.value)
}
}
}