ios - Swift `Decodable` 不适用于嵌套的 JSON 对象,除非嵌套是一个数组

标签 ios json swift swift4 codable

我已经开始转换一些 JSON 解析代码以使用新的 Apple Decodable 协议(protocol),并且遇到了一个感觉太基础的拦截器,在 Apple 的测试期间不会被遗漏,所以我想知道我是否做傻事。 简而言之,我正在尝试解析这样的 JSON 图,因为我只是在解码,所以我认为符合 Decodable 应该就足够了,但从错误来看,我需要符合 Codable (Decodable & Encodable) 以获得所需的解码效果:

{"keyString": {"nestedKey1" : "value1", "nestedKey1" : "value1" } }

它适用于这种情况:

{"keyString": [{"nestedKey1" : "value1", "nestedKey1" : "value1" } ]}

嵌套对象数组,但不是单个对象。

这是 Swift 的错误还是我做错了什么?

这是一个可以证明问题的示例 Playground 。如果 Animal 类符合 Decodable,它不会解析数组大小写,但如果我将 Animal 设置为符合 Codable,那么它就可以工作。我不希望出现这种情况,因为我在这里只解码 JSON。

import Foundation

//class Animal: Codable {    
class Animal: Decodable {
    var fileURLPath: String = ""
    var age: Double = 0
    var height: Double = 0
    var weight: Double = 0

    private enum CodingKeys: String, CodingKey {
        case fileURLPath = "path"
        case age
        case height
        case weight
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        fileURLPath = try values.decode(String.self, forKey: .fileURLPath)
        age = try values.decode(TimeInterval.self, forKey: .age)
        height = try values.decode(Double.self, forKey: .height)
        weight = try values.decode(Double.self, forKey: .weight)
    }
}

let innerObjectJSON = """
{
    "path": "tiger_pic.png",
    "age": 9,
    "height": 1.23,
    "weight": 130
}
"""

let innerObjectData = innerObjectJSON.data(using: String.Encoding.utf8)

let jsonDataNestedObject = """
    { "en" : \(innerObjectJSON)
    }
    """.data(using: String.Encoding.utf8)

let jsonDataNestedArray = """
    { "en" : [\(innerObjectJSON), \(innerObjectJSON), \(innerObjectJSON) ]
    }
    """.data(using: String.Encoding.utf8)

print("Nested Array of Objects:")

do {
    let result = try JSONDecoder().decode([String: [Animal]].self, from: jsonDataNestedArray!)
    result["en"]!.forEach ({ print($0.fileURLPath) }) // This one works
} catch { print(error) }

print("\n\n Single Object:")
do {
    let result = try JSONDecoder().decode(Animal.self, from: innerObjectData!)
        print(result.fileURLPath)
} catch { print(error) }

print("\n\nNested Object:")
do {
    let result = try JSONDecoder().decode([String: Animal].self, from:jsonDataNestedObject!)
        print(result["en"]!.fileURLPath) // I would also expect this to work but I get the error: "fatal error: Dictionary<String, Animal> does not conform to Decodable because Animal does not conform to Decodable.: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.45.6/src/swift/stdlib/public/core/Codable.swift, line 3420"
} catch { print(error) }

最佳答案

如果你不想等到下一个版本,你可以使用一个struct:

import Cocoa

struct Animal: Codable {
    var fileURLPath: String
    var age: Double
    var height: Double
    var weight: Double

    private enum CodingKeys: String, CodingKey {
        case fileURLPath = "path"
        case age, height, weight
    }
}

let innerObjectJSON = """
{
"path": "tiger_pic.png",
"age": 9,
"height": 1.23,
"weight": 130
}
"""

let innerObjectData = innerObjectJSON.data(using: String.Encoding.utf8)

let jsonDataNestedObject = """
    { "en" : \(innerObjectJSON)
    }
    """.data(using: String.Encoding.utf8)


print("\n\nNested Object:")
do {
    let result = try JSONDecoder().decode([String: Animal].self, from:jsonDataNestedObject!)
    print(result["en"]!.fileURLPath) 
} catch { print(error) }

这给了我

Nested Object:
tiger_pic.png
["en": __lldb_expr_190.Animal(fileURLPath: "tiger_pic.png", age: 9.0, height: 1.23, weight: 130.0)]

它很容易解码,但是它不使用 TimeInterval,不过它只是 Double 的别名。

关于ios - Swift `Decodable` 不适用于嵌套的 JSON 对象,除非嵌套是一个数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44706112/

相关文章:

ios - 处理日光时差

ios - ionic 地理定位,在 iOS 上没有权限

ios - 如何使用 Swift 跨 ViewControllers 继续一个功能?

mysql - 在 MySQL 中使用 Json 键值对对象查找和替换字符串

javascript - 如何使用双for循环从json中检索过滤后的数据

ios - 在容器 View 中播放本地视频 Swift 4

iOS : 'MyViewController' does not conform to protocol 'UITableViewDataSource'

google-maps - 使用谷歌地图获取附近的地方

ios - Pod 未在 Pods 文件中列出,但它安装在 pod install 命令上

ruby-on-rails - rails 3 as_json :only or :methods option do not work with dynamic attributes