【问题标题】:Swift Convert UnionValue JSON to Object and loopSwift将UnionValue JSON转换为对象并循环
【发布时间】:2021-11-26 15:31:16
【问题描述】:

收到 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'”。请帮忙。

【问题讨论】:

  • 我复制/粘贴了您的代码,我得到“从 'ValueUnion' 转换为不相关类型 '[ValueElement]' 总是失败”,而不是您的错误...
  • 是的,我想转换为 [ValueElement] 以便循环播放。
  • 您必须将您的 JSON 响应转换为您的模型对象,如下所示:- let decoder = JSONDecoder() do { let people = try decoder.decode(ModelName.self, from: result.value) print (人) } 捕捉 { 打印(error.localizedDescription) }
  • 你也可以删除结构体旁边的代码......从枚举开始到结束

标签: ios json swift


【解决方案1】:

你应该得到的编译器错误:

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
}

【讨论】:

  • 使用开关在项目上工作。感谢您的支持。
【解决方案2】:

您的 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)
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-20
    • 2017-06-16
    • 1970-01-01
    • 2019-09-28
    • 2016-12-24
    • 2018-02-24
    • 2017-08-24
    相关资源
    最近更新 更多