基于另一个值的具有多个对象类型的可编码解码属性

2023-12-14

这不是关于解码具有多种类型(int、string)的属性值。

我有一个名为data它可以返回多种类型,此时可以执行的操作可能如下所示:

enum MyData: Codable {
    case ObjOne(groupObject)
    case ObjTwo(imageObject)

    init(from decoder: Decoder) throws {
        let value = try decoder.singleValueContainer()

        if let v = try? value.decode(groupObject.self) {
            self = .ObjOne(v)
            return
        } else if let v = try? value.decode(imageObject.self) {
            self = .ObjTwo(v)
            return
        }

        throw Rating.ParseError.notRecognizedType(value)
    }

    enum ParseError: Error {
        case notRecognizedType(Any)
    }
}

这里的问题是我试图让MyData根据先前解码过程中使用的另一个值来解码对象,简而言之,我想将一个值传递给MyData这样它就可以确定要解码哪个

我有这个

enum ContentType: String, Codable {
    case linear
    case grid
    case slider
}

而且我要MyData知道这个ContentType如此看重MyData可以确定流量将如何流动,

那么 ContentType 从哪里来呢?它与前一个主对象的属性列表相同,来自如下所示的内容

struct Catalog: Codable {
    var dataType: ContentType?
    var data: MyData? 
}

我想用更简单的话实现什么?

struct Catalog: Codable {
    var dataType: ContentType?
    var data: MyData<dataType>? <--// i know this is not possible,
    // -- but i want MyData to know about the dataType value that will be decoded
}

--------- 我要解析的 JSON

[{
  "data_type": "group",
  "data": {
    "group_id": 127 // this refers to object : groupObject
  }
},
{
  "data_type": "image",
  "data": {
    "image": "http://google.com/favicon" // this is referring : imageObject
  }
}
]

你看上面的一点,就是“数据”可以返回不同的对象,基于 data_type 的值


我没有使用泛型,而是创建了一个符合以下条件的空协议Decodable并用它作为类型data。那么内容结构需要符合这个协议。

protocol MyData: Decodable {}

struct Group: MyData {
    let groupId: Int
}

struct Image: MyData {
    let image: String
}

struct Catalog: Decodable {
    var dataType: String
    var data: MyData

    enum CodingKeys: String, CodingKey  {
        case dataType, data
    }

    enum ParseError: Error {
        case notRecognizedType(Any)
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        dataType = try container.decode(String.self, forKey: .dataType)
        switch dataType {
        case "group":
            data = try container.decode(Group.self, forKey: .data)
        case "image":
            data = try container.decode(Image.self, forKey: .data)
        default:
            throw ParseError.notRecognizedType(dataType)
        }
    }
}

请注意,我没有使用枚举ContentType in the init因为它与示例 json 数据不匹配,但这应该很容易修复。

使用此解决方案的标准代码

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase

    let result = try decoder.decode([Catalog].self, from: data)
    print(result)
} catch {
    print(error)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于另一个值的具有多个对象类型的可编码解码属性 的相关文章

随机推荐