ios - 使用 JSONDecoder 解码带有空对象的 JSON

标签 ios json swift foundation jsondecoder

我想使用 JSONDecoder 解码 JSON。它按预期工作,但对于内部对象为空的 JSON,JSONDecoder 会抛出错误由于缺少数据而无法读取数据。

错误时的 JSON 示例:

{
    "header": {
        "code": 1053,
        "message": "Incorrect information."
    },
    "body": {}
}

成功时的 JSON 示例:

{
    "header": {
        "code": 1053
        "message": "Nice information."
    },
    "body": {
        "client_id": 12345
    }
}

成功的JSON,很容易解码。但在 Error JSON 上,它抛出错误。

这是我正在使用的代码

struct ApiResponse: Decodable {

    let header: Header
    let body: Body

    struct Header: Decodable {
        let responseCode: Int
        let message: String
    }

    struct Body: Decodable {
        let clientId: Int
    }
}

let decoder: JSONDecoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decodedResponse = try decoder.decode(ApiResponse.self, from: data)

最佳答案

您可以扩展KeyedDecodingContainer,以使用协议(protocol)将空字典视为nil

public protocol EmptyDictionaryRepresentable {
    associatedtype CodingKeys : RawRepresentable where CodingKeys.RawValue == String
    associatedtype CodingKeyType: CodingKey = Self.CodingKeys
}

extension KeyedDecodingContainer {
    public func decodeIfPresent<T>(_ type: T.Type, forKey key: KeyedDecodingContainer.Key) throws -> T?
        where T : Decodable & EmptyDictionaryRepresentable
    {
        guard contains(key) else { return nil }
        let container = try nestedContainer(keyedBy: type.CodingKeyType.self, forKey: key)
        return container.allKeys.isEmpty ? nil : try decode(T.self, forKey: key)
    }
}

要使用它,请采用协议(protocol)并将受影响的属性声明为可选

struct ApiResponse: Decodable {
    let header: Header
    let body: Body?
}

struct Body: Decodable, EmptyDictionaryRepresentable {
    enum CodingKeys : String, CodingKey { case clientId = "client_id" }

    let clientId: Int
}

警告:此解决方案不适用于 .convertFromSnakeCase 策略

注意:考虑 Header 中的键 - 结构成员名称不匹配

关于ios - 使用 JSONDecoder 解码带有空对象的 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60061276/

相关文章:

php - 如何使用 JSON 从 MYSQL 中的 select 插入数据?

swift - 将 4 个字节的 (Swift3) 数据放入 UInt32 的两种方法

ios - 仅绕一个轴旋转节点

iphone - 如何确定 UINavigationController 中工具栏的高度?

ios - 使用 UIModalPresentationCustom 在 ModalViewController 中设置框架 iOS8

ios - 隐藏 TableView 中原型(prototype)单元的标签

ios - 关闭 UIDocumentPicker 时出错

javascript - JSON AngularJS 中的图像

python - 无法在自定义编码器中将字典编码为 JSON

ios - UITableView 不填充数据