Swift 4 JSON Codable - 返回的值有时是一个对象,其他的则是一个数组 [英] Swift 4 JSON Codable - value returned is sometimes an object, others an array

查看:39
本文介绍了Swift 4 JSON Codable - 返回的值有时是一个对象,其他的则是一个数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从 API 获取的数据返回单个对象,但是当有多个对象时,它返回一个包含相同键的数组.使用我正在使用的当前模型(结构),当数组出现时解码失败.

the data I'm getting from an API returns a single object but when there's multiple objects, it returns an array in the same key. With the current model (struct) I'm working with, the decoding fails when an array shows up.

这些结果是随机排序的,这意味着我不知道什么时候会收到一个对象或数组.

These results are randomly ordered, meaning I can't know when I will be served an object or array.

是否有一种方法可以创建一个模型,该模型将这一事实考虑在内,并可以分配正确的类型来转换值('String' 或 '[String]'),以便继续解码而不会出现问题?

Is there a way to create a model that takes this fact into account and can assign the correct type to cast for the value ('String' or '[String]') so that the decoding continues without problem?

这是返回对象时的示例:

This is an example of when an object is returned:

{
    "firstFloor": {
        "room": "Single Bed"
    }
}

这是返回数组时的示例(对于相同的键):

This is an example of when an array is returned (for the same key):

{
    "firstFloor": {
        "room": ["Double Bed", "Coffee Machine", "TV", "Tub"]
    }
}

应该能够用作模型来解码上述两个样本的结构示例:

Example of the struct that should be able to be used as model to decode both samples above:

struct Hotel: Codable {
    let firstFloor: Room

    struct Room: Codable {
        var room: String // the type has to change to either array '[String]' or object 'String' depending on the returned results
    }
}

这些结果是随机排序的,这意味着我不知道什么时候会收到一个对象或数组.

These results are randomly ordered, meaning I can't know when I will be served an object or array.

这是完整的游乐场文件:

Here is the complete playground file:

import Foundation

// JSON with a single object
let jsonObject = """
{
    "firstFloor": {
        "room": "Single Bed"
    }
}
""".data(using: .utf8)!

// JSON with an array instead of a single object
let jsonArray = """
{
    "firstFloor": {
        "room": ["Double Bed", "Coffee Machine", "TV", "Tub"]
    }
}
""".data(using: .utf8)!

// Models
struct Hotel: Codable {
    let firstFloor: Room

    struct Room: Codable {
        var room: String // the type has to change to either array '[String]' or object 'String' depending on the results of the API
    }
}

// Decoding
let decoder = JSONDecoder()
let hotel = try decoder.decode(Hotel.self, from: jsonObject) //

print(hotel)

推荐答案

您可以使用带有关联值(在本例中为字符串和数组)的枚举来封装结果的歧义,例如:

You might encapsulate the ambiguity of the result using an Enum with Associated Values (String and Array in this case), for example:

enum MetadataType: Codable {
    case array([String])
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            self = try .array(container.decode(Array.self))
        } catch DecodingError.typeMismatch {
            do {
                self = try .string(container.decode(String.self))
            } catch DecodingError.typeMismatch {
                throw DecodingError.typeMismatch(MetadataType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Encoded payload not of an expected type"))
            }
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .array(let array):
            try container.encode(array)
        case .string(let string):
            try container.encode(string)
        }
    }
}

struct Hotel: Codable {
    let firstFloor: Room

    struct Room: Codable {
        var room: MetadataType
    }
}

这篇关于Swift 4 JSON Codable - 返回的值有时是一个对象,其他的则是一个数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆