如何从 Swift 4 中的 Decoder 容器获取未解码的属性?

2024-01-27

我正在使用Decodable协议以便解析从外部源接收到的 JSON。解码我所知道的属性后,JSON 中可能仍然有一些未知且尚未解码的属性。例如,如果外部源在未来某个时间点向 JSON 添加了新属性,我希望通过将这些未知属性存储在[String: Any]字典(或替代方案),这样值就不会被忽略。

问题是,在解码我所知道的属性后,容器上没有任何访问器来检索尚未解码的属性。我知道decoder.unkeyedContainer()我可以用它来迭代每个值,但这在我的情况下不起作用,因为为了使其工作,您需要知道要迭代的值类型,但 JSON 中的值类型并不总是相同。

这是我想要实现的游乐场中的一个示例:

// Playground
import Foundation

let jsonData = """
{
    "name": "Foo",
    "age": 21
}
""".data(using: .utf8)!

struct Person: Decodable {
    enum CodingKeys: CodingKey {
        case name
    }

    let name: String
    let unknownAttributes: [String: Any]

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

        // I would like to store the `age` attribute in this dictionary
        // but it would not be known at the time this code was written.
        self.unknownAttributes = [:]
    }
}

let decoder = JSONDecoder()
let person = try! decoder.decode(Person.self, from: jsonData)

// The `person.unknownAttributes` dictionary should
// contain the "age" attribute with a value of 21.

我想为unknownAttributes字典来存储age本例中的属性和值以及任何其他可能的值类型(如果将来从外部源添加到 JSON)。

我想做这样的事情的原因是,我可以保留 JSON 中存在的未知属性,以便在将来的代码更新中,一旦属性键已知,我就能够正确处理它们。

我在 StackOverflow 和 Google 上进行了大量搜索,但尚未遇到这种独特的情况。提前致谢!


你们不断想出新的方法来强调 Swift 4 编码 API...;)

通用解决方案,支持all值类型,可能不可能。但是,对于原始类型,您可以尝试以下操作:

创建一个简单的CodingKey使用基于字符串的键键入:

struct UnknownCodingKey: CodingKey {
    init?(stringValue: String) { self.stringValue = stringValue }
    let stringValue: String

    init?(intValue: Int) { return nil }
    var intValue: Int? { return nil }
}

然后使用标准编写通用解码函数KeyedDecodingContainer密钥由UnknownCodingKey above:

func decodeUnknownKeys(from decoder: Decoder, with knownKeys: Set<String>) throws -> [String: Any] {
    let container = try decoder.container(keyedBy: UnknownCodingKey.self)
    var unknownKeyValues = [String: Any]()

    for key in container.allKeys {
        guard !knownKeys.contains(key.stringValue) else { continue }

        func decodeUnknownValue<T: Decodable>(_ type: T.Type) -> Bool {
            guard let value = try? container.decode(type, forKey: key) else {
                return false
            }
            unknownKeyValues[key.stringValue] = value
            return true
        }
        if decodeUnknownValue(String.self) { continue }
        if decodeUnknownValue(Int.self)    { continue }
        if decodeUnknownValue(Double.self) { continue }
        // ...
    }
    return unknownKeyValues
}

最后,使用decodeUnknownKeys功能来填补你的unknownAttributes字典:

struct Person: Decodable {
    enum CodingKeys: CodingKey {
        case name
    }

    let name: String
    let unknownAttributes: [String: Any]

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

        let knownKeys = Set(container.allKeys.map { $0.stringValue })
        self.unknownAttributes = try decodeUnknownKeys(from: decoder, with: knownKeys)
    }
}

一个简单的测试:

let jsonData = """
{
    "name": "Foo",
    "age": 21,
    "token": "ABC",
    "rate": 1.234
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let person = try! decoder.decode(Person.self, from: jsonData)
print(person.name)
print(person.unknownAttributes)

prints:

Foo
[“年龄”:21,“代币”:“ABC”,“比率”:1.234]

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

如何从 Swift 4 中的 Decoder 容器获取未解码的属性? 的相关文章

  • AngularJS - 从数据中删除 \n

    捕获和格式化从服务器传递的文本内部以显示换行符的最佳方法是什么 小提琴在这里 http jsfiddle net nicktest2222 2vYBn http jsfiddle net nicktest2222 2vYBn scope d
  • WKWebView 截图

    我正在尝试捕获网络视图向用户显示的图像 以便我可以对网页进行一些颜色分析 当我尝试从其父级获取图像时 即使页面已呈现 我基本上也会得到一个白框 func makeImageSnapshot gt NSImage let imgSize se
  • 如何在ios开发中从mp3文件中提取元数据

    我正在开发一个带有云存储的 ios 音乐播放器 我需要提取音乐信息 如标题 艺术家 艺术作品 我有一个名为 playit 的操作 可以播放和暂停 mp3 文件 它还应该使用与 mp3 文件关联的元数据来填充一些 UILables 和 UII
  • iOS8 自签名证书已安装但仍不受信任

    由于我无法控制的原因 我需要使用自签名证书针对平台进行 iOS 开发 它是一个在 SAN 中具有特定 IP 地址的根证书 当证书安装在 OSX 系统帐户下时 所有浏览器现在将正常信任对给定 IP 地址的任何访问 通过电子邮件将同一证书发送到
  • jQuery.getJSON:如何避免在每次刷新时请求 json 文件? (缓存)

    在此示例中 您可以看到生成的 HTML 列表 每次刷新时 脚本都会请求数据文件 ajax test json 并再次构建列表 生成的文件 ajax test json 被静态缓存 但是如何避免在每次刷新时请求此文件 source jquer
  • 每次打开应用程序时,FileManager 的路径 URL 都不同[重复]

    这个问题在这里已经有答案了 我想在fileManager根路径中创建一个文件夹 但在创建之前 我想检查该文件夹是否存在 如果不存在 我将创建 否则将保留它 这是我使用的功能 public func isDirectoryExist path
  • 读取google地图返回的JSON数据

    在我的应用程序中 我使用 BlackBerry API 来获取纬度和经度 我想通过创建 http 连接使用 Google 地图进行反向地理编码 如何解析数据 然后读取特定元素 例如地址 示例网址 给出回应 name 9 600000 76
  • 将时间舍入到最接近的三十秒

    我有一个应用程序 它显示每 30 秒过期的数据 准确地说 在 h m s 11 30 00 11 30 30 11 31 00 等 我可以获得当前时间 但我不确定如何计算现在到最近的三十秒之间的时间 我发现的所有内容都是 Objective
  • Spring Rest POST Json RequestBody 不支持内容类型

    当我尝试使用 post 方法发布新对象时 RequestBody 无法识别 contentType Spring 已经配置完毕 POST 可以与其他对象一起使用 但不能与这个特定对象一起使用 org springframework web
  • AST 文件格式错误或损坏

    我有一个问题 我不知道为什么会发生这种情况 但很可能是因为我错误地按了 移动到垃圾箱 到某些系统框架 我收到一条错误消息 AST 文件格式错误或损坏 找不到 AST 文件引用的文件 Users username myProject Quar
  • 如何在复杂的层次结构中上下同步 CALayer 和 UIView 动画

    See 如何在整个层次结构中管理 CALayer 动画 https stackoverflow com questions 26917908 how to manage calayer animations throughout a hie
  • -[_SwiftValueencodeWithCoder:]:无法识别的选择器发送到实例

    尝试使用 NSCoder 时出现错误 玩家 swift class Player NSObject NSCoding private var playerName String private var playerScore Int pri
  • 辅助功能标识符在 iOS 模拟器的辅助功能检查器中不可见

    我想使用辅助功能检查器来验证在模拟器 iOS 9 2 中运行的应用程序中的所有辅助功能标识符 辅助功能检查器能够返回多个辅助功能字段 但不能返回标识符 知道为什么以及如何我能看到它们吗 实际上有一种方法 克里斯 普林斯 Chris Prin
  • 使用 CouchDB 提供 HTML 服务

    我正在尝试将 CouchDB 与 HTML 独立 REST 架构一起使用 也就是说 除了 CouchDB 和 ajax 风格的 javascript 调用 CouchDB 之外 没有其他应用程序服务器 看起来交叉脚本是一个问题 我之前使用过
  • Postman - 如何计算 JSON 响应中特定对象的出现次数

    我是 JSON 和 Postman 的新手 我相信我正在尝试做一些非常简单的事情 我创建了一个 GET 请求 它将获得如下所示的 JSON 响应 在下面的例子中我想得到count响应中所有 IsArchived 属性 这些属性的数量因响应而
  • ThreeJS无法加载Json文件

    首先 我已经读过这个问题 https stackoverflow com questions 17201888 three js exporter export object not working with jsonloader r58没
  • ios swift 如何将默认语言设置为阿拉伯语?

    我正在开发一个有两种语言的应用程序 即英语和阿拉伯语 我用英语编写了该应用程序 然后用阿拉伯语本地化了该应用程序 更改语言时需要重新启动应用程序 我唯一的问题是 第一次安装应用程序时如何将默认语言设置为阿拉伯语 我尝试在编辑方案部分将语言设
  • 在 Swift 中将 xib 分配给 UIView

    在 Objective C 中 它可以在 init 方法中完成 id init self NSBundle mainBundle loadNibNamed ViewBtnWishList owner 0 options nil object
  • 在启动屏幕中执行代码已更新

    在原始启动屏幕中执行代码 https stackoverflow com questions 27642016 execute code in launch screen 现在默认的LaunchScreenXcode 项目中的文件已更改为
  • 如何在 Swift 中将所有 iOS 设备的标签水平居中

    我不知道如何使标签在图像视图中水平居中 标签说 You ve been here What would you rate us 我想要What would you rate us属于 You ve been here 我试图完成此操作的方法

随机推荐