Received Json response
{
"data": [
{
"key": "email",
"value": "[email protected]"
},
{
"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"
}
Generated model using online tool
// 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
}
Try to access the address array in the model. but always fails
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)
}
I want to loop through the key and values of address. but am getting error "For-in loop requires 'ValueUnion' to conform to 'Sequence'" . please help.
CodePudding user response:
The compiler error you should get on:
guard let address_info = item.value as? [ValueElement] else { return }
is
Cast from 'ValueUnion' to unrelated type '[ValueElement]'
Not "For-in loop requires 'ValueUnion' to conform to 'Sequence'".
The error is explicit, address_info
is a ValueUnion, not a [ValueElement]
. In your specific case, it's almost that, but since it's a ValueUnion
, it could be a String
instead.
Afterall, ValueUnion
is a associated value enum to handle a String and a Array of ValueElement
.
The quick "fix" would be:
if case let .valueElementArray(address_info) = item.value {
for ad in address_info {
print(ad.key)
print(ad.value)
}
}
But it might be too advanced (and isn't useful if you don't understand it).
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)
}
}
Now, your JSON is strange, and you might want in the end a model, so either have a "mapping" beetween you current model into that one, or with some work (maybe too much work for the result), decode directly into this model.
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
}
CodePudding user response:
Your ValueUnion could be one of two distinct values, either a single String, or an array of key/value pairs. You say you "want to cast to [ValueElement]" so you can loop through them, but what if the ValueUnion doesn't contain an array of value elements?
First you have to find out if an array even exists in the value union...
func example(valueUnion: ValueUnion) {
if case let .valueElementArray(array) = valueUnion {
for each in array {
print("valueElement - key:", each.key, " value:", each.value)
}
}
}