如何解码类型取决于标签的值数组?

2023-11-21

我有一个包含值数组的 JSON:

[
    { "tag": "Foo", … },
    { "tag": "Bar", … },
    { "tag": "Baz", … },
]

我想将这个数组解码为一个数组struct其中特定类型取决于标签:

protocol SomeCommonType {}

struct Foo: Decodable, SomeCommonType { … }
struct Bar: Decodable, SomeCommonType { … }
struct Baz: Decodable, SomeCommonType { … }

let values = try JSONDecoder().decode([SomeCommonType].self, from: …)

我怎么做?目前我有这个有点难看的包装:

struct DecodingWrapper: Decodable {

    let value: SomeCommonType

    public init(from decoder: Decoder) throws {
        let c = try decoder.singleValueContainer()
        if let decoded = try? c.decode(Foo.self) {
            value = decoded
        } else if let decoded = try? c.decode(Bar.self) {
            value = decoded
        } else if let decoded = try? c.decode(Baz.self) {
            value = decoded
        } else {
            throw …
        }
    }
}

进而:

let wrapped = try JSONDecoder().decode([DecodingWrapper].self, from: …)
let values = wrapped.map { $0.value }

有没有更好的办法?


您的数组包含有限的、可枚举的种类的异构对象;听起来像是 Swift 枚举的完美用例。它不适合多态,因为从概念上讲,这些“东西”不一定是同一类。他们只是碰巧被标记了。

这样看:你有一系列带有标签的东西,有些是这种类型,有些是完全不同的类型,还有一些......有时你甚至不认识标签。 Swift 枚举是体现这一想法的完美工具。

所以你有一堆共享标签属性但在其他方面彼此完全不同的结构:

struct Foo: Decodable {
    let tag: String
    let fooValue: Int
}

struct Bar: Decodable {
    let tag: String
    let barValue: Int
}

struct Baz: Decodable {
    let tag: String
    let bazValue: Int
}

并且您的数组可以包含上述类型或未知类型的任何实例。所以你有枚举TagggedThing(或者更好的名字)。

enum TagggedThing {
    case foo(Foo)
    case bar(Bar)
    case baz(Baz)
    case unknown
}

用 Swift 术语来说,你的数组属于类型[TagggedThing]。所以你符合TagggedThing键入至Decodable像这样:

extension TagggedThing: Decodable {
    private enum CodingKeys: String, CodingKey {
        case tag
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let tag = try container.decode(String.self, forKey: .tag)

        let singleValueContainer = try decoder.singleValueContainer()
        switch tag {
        case "foo":
            // if it's not a Foo, throw and blame the server guy
            self = .foo(try singleValueContainer.decode(Foo.self))
        case "bar":
            self = .bar(try singleValueContainer.decode(Bar.self))
        case "baz":
            self = .baz(try singleValueContainer.decode(Baz.self))
        default:
            // this tag is unknown, or known but we don't care
            self = .unknown
        }
    }
}

现在您可以解码以下 JSON:

let json: Data! = """
[
    {"tag": "foo", "fooValue": 1},
    {"tag": "bar", "barValue": 2},
    {"tag": "baz", "bazValue": 3}
]
""".data(using: .utf8)

像这样:

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

如何解码类型取决于标签的值数组? 的相关文章

  • SKNode 上的 runAction 未完成

    我使用 NSOperation 子类来获取串行执行SKAction正如这个问题中所描述的 如何在 Swift 中子类化 NSOperation 以将 SKAction 对象排队以进行串行执行 https stackoverflow com
  • Swift C 回调 - Swift 类指针的 takeUnretainedValue 或 takeRetainedValue

    我有一些UIView or UITableViewCell 里面我有 C 回调 例如 CCallback bridge self observer data gt Void in let mySelf Unmanaged
  • IPV6 快速可达性

    我是 swift 和 xcode 的新手 并且我的应用程序因 IPV6 而被拒绝 性能 2 1 当我们执行以下操作时 您的应用程序会在运行 iOS 9 3 5 并连接到 IPv6 网络的 iPad 和 iPhone 上崩溃 具体来说 当我们
  • 在视图控制器之间传递数据使用从嵌入导航控制器的视图到 tabbarcontroller 的 Segue

    我有两个视图 我想将数据从一个视图传递到下一个视图 第一个视图是我想要传递给下一个视图的数据的地方 我们称之为SourceViewController 然而SourceViewController嵌入在一个NavigationViewCon
  • 使用 UISearchBar 过滤数组

    我目前正在使用以下代码来过滤数组并将结果显示在我的 tableView 中 问题是 只有当搜索与确切的单词匹配时 才会返回结果 如何更改数组过滤器以在输入时搜索每个字符 let data Mango Grape Berry Orange A
  • 将嵌套字典键值转换为 pyspark 数据帧

    我有一个 Pyspark 数据框 如下所示 我想提取 dic 列中的那些嵌套字典并将它们转换为 PySpark 数据帧 像这样 请让我知道如何实现这一目标 Thanks from pyspark sql import functions a
  • 在 swrevealcontroller 之前实现登录屏幕

    我刚刚开始学习 IOS 开发 我已经按照给定的在线教程成功实现了 SWRevealViewController 一切都按预期工作 然后 我决定添加一个登录屏幕 这将是应用程序运行时用户看到的第一个页面 我采取的步骤如下 将 UIViewCo
  • Haskell Data.Decimal 作为 Aeson 类型

    是否可以解析一个数据 十进制 https hackage haskell org package Decimal 0 4 2 docs Data Decimal html使用 Aeson 包从 JSON 获取 假设我有以下 JSON foo
  • 从 php 到 JavaScript 的数组

    我正在尝试使用 json 将数组列表从 php 传输到 javascript 但它不起作用 JS ajax url getProfilePhotos php type post post or get method data if you
  • 如何自动缩放mapView以显示叠加层

    我可以在 mapView 上绘制多边形 但是我需要找到多边形并手动缩放它 有没有办法自动执行此过程 例如调整中心多边形 我浏览过互联网并阅读了一些相关文章 其中大多数都是基于折线和点的 任何形式的帮助将不胜感激 因为我正在寻找解决方案一段时
  • 在 iOS 11 中创建 Gif 图像颜色贴图

    最近 我在创建 Gif 时遇到了一个问题 如果它太大 颜色就会丢失 然而 感谢 SO 的帮助 有人能够帮助我找到解决方法并创建我自己的颜色图 上一个问题在这里 保存动画 Gif 时 iOS 颜色不正确 https stackoverflow
  • 如何在 Swift 3 中解析 JSON 数组 [重复]

    这个问题在这里已经有答案了 我从 Socket 获取了一些我想访问的数据 但收到错误消息 指出每次都无法将 NSArray 转换为 NSDictionary struct SocketEventHandler let event Strin
  • JSON 解析错误:需要“STRING”

    我在用JSONLint http jsonlint com 解析一些 JSON 我不断收到错误 错误 第 1 行解析错误 产品 需要 STRING 却得到 未定义 这是代码 product code Abc123 description S
  • 如何使用正则表达式将字符串分成相同字符的组?

    我有一个这样的字符串 var string AAAAAAABBBCCCCCCDD 并喜欢将字符串分割成这种格式的数组 same characters gt same group 使用正则表达式 Array AAAAAAA BBB CCCCC
  • 从 JSON 响应中删除元素

    我有一个 JSON 字符串 我希望能够从中删除一些数据 以下是 JSON 响应 ResponseType VirtualBill Response BillHeader BillId 7134 DocumentId MN003 052206
  • Swift getnameinfo IPv6 结果不可靠

    我有以下扩展sockaddr extension sockaddr Indicates if this is an IPv4 address var isIPv4 Bool return sa family UInt8 AF INET In
  • 无法转换“UINavigationController”类型的值

    我正在为我的应用程序实现一个搜索界面 因此基本上我会将搜索关键字从一个 ViewController 传递到另一个 ViewController 我已经多次进行过这种类型的参数传递 但这次似乎有些奇怪 目标 ViewController 嵌
  • 通过标识引用对象的标准方法(例如循环引用)?

    JSON 中是否有通过身份引用对象的标准方法 例如 具有大量 可能是循环 引用的图形和其他数据结构可以被合理地序列化 加载吗 Edit 我知道做一次性解决方案很容易 列出图中所有节点的列表 然后 我想知道是否有一个标准的 通用的解决方案来解
  • JSON 数组到 C# 列表

    如何将这个简单的 JSON 字符串反序列化为 C 中的列表 on4ThnU7 n71YZYVKD CVfSpM2W 10kQotV 这样 List
  • NSPredicate 的 onFormat 字符串

    我想用 id 键对数据进行排序 我如何理解格式字符串的用途NSPredicate格式 我有一个100号的帖子 我的代码 let objectIDs posts map 0 id let predicate NSPredicate forma

随机推荐