Получен ответ 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)
            
        }

Я хочу пройтись по ключам и значениям адреса. но я получаю сообщение об ошибке: «Цикл For-in требует, чтобы« ValueUnion »соответствовал« Sequence »». пожалуйста помоги.

-1
Sathya Baman 6 Окт 2021 в 15:43

2 ответа

Лучший ответ

Ошибка компилятора, на которую вы должны попасть:

guard let address_info = item.value as? [ValueElement] else { return }

Является

Cast from 'ValueUnion' to unrelated type '[ValueElement]'

Не «Цикл For-in требует, чтобы 'ValueUnion' соответствовал 'Sequence'».

Ошибка явная, address_info является ValueUnion, а не [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
Larme 6 Окт 2021 в 13:20

Ваш ValueUnion может быть одним из двух различных значений, либо одной строкой, либо массивом пар ключ / значение. Вы говорите, что «хотите привести к [ValueElement]», чтобы можно было их просмотреть в цикле, но что, если ValueUnion не содержит массива элементов значений?

Сначала вам нужно выяснить, существует ли вообще массив в объединении значений ...

func example(valueUnion: ValueUnion) {
    if case let .valueElementArray(array) = valueUnion {
        for each in array {
            print("valueElement - key:", each.key, " value:", each.value)
        }
    }
}
1
Daniel T. 6 Окт 2021 в 13:55