【问题标题】:Swift 4.2 - Decode JSON Where Same Key Is Different TypeSwift 4.2 - 解码相同键不同类型的 JSON
【发布时间】:2019-07-28 02:29:33
【问题描述】:

我正在使用以下模型解码对象

struct ACDeviceLastData {
    var DA: ACDeviceLastDataBody = ACDeviceLastDataBody()
}

struct ACDeviceLastDataBody {
    var amOn: Bool = false
    var enabledZones: [Int] = []
    var fanSpeed: Int = 0
    var mode: Int = 0
    var tempTarget: Float = 0.00
}

extension ACDeviceLastData: Decodable {
        init(from decoder: Decoder) throws {
            //Create Container
            let container = try decoder.container(keyedBy: ACDeviceCodingKeys.self)

        //Decode Data
        DA = try container.decodeIfPresent(ACDeviceLastDataBody.self, forKey: .DA) ?? ACDeviceLastDataBody()
    }
}

extension ACDeviceLastDataBody: Decodable {
    init(from decoder: Decoder) throws {
        //Create Container
        let container = try decoder.container(keyedBy: ACDeviceCodingKeys.self)

        //Decode Data
        amOn = try container.decodeIfPresent(Bool.self, forKey: .amOn) ?? false
        enabledZones = try container.decodeIfPresent([Int].self, forKey: .enabledZones) ?? []
        fanSpeed = try container.decodeIfPresent(Int.self, forKey: .fanSpeed) ?? 0
        mode = try container.decodeIfPresent(Int.self, forKey: .mode) ?? 0
        tempTarget = try container.decodeIfPresent(Float.self, forKey: .tempTarget) ?? 0.00
    }
}

这样做的问题是DA 的值并不总是相同的类型。它有时可以是整数数组的格式,有时可以是 ACDevieLastDataBody 的格式。我试过做一个 do-try-catch ,但不知道如何让它发挥作用(如果这甚至是正确的做法)

我的问题是,当它是一个整数数组时,我将如何在没有解码器抛出的情况下解码它们。非常感谢任何帮助。提前谢谢你。

【问题讨论】:

  • 捕获init方法中的类型不匹配错误,如果发生则解码其他类型。或者使用具有关联类型的枚举来区分情况。
  • @vadian 感谢您的建议。您是否有机会为我发布一个示例,因为我不能 100% 确定您将如何实施?
  • 这个问题已经问过了a couple of times

标签: ios json rest swift4


【解决方案1】:

需要在init(from decoder: Decoder)中排列类型

这是一个简单的转换,注意类型可能不完全一样,所以兼容性是你的安排,你的负担。

我看不到 JSON,但 JSON to Code 很容易做到,因为 JSON 类型在原子级别上总是很简单。

希望对你有帮助……

你有一个美好的一天!

【讨论】:

    【解决方案2】:

    首先,您必须选择一种存储数据的方式。为简单起见,我们将Int 的数组存储为单独的属性:

    struct ACDeviceLastData {
       var DA: ACDeviceLastDataBody = ACDeviceLastDataBody()
       var DAasInts: [Int] = []
    }
    
    extension ACDeviceLastData: Decodable {
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: ACDeviceCodingKeys.self)
    
            if let ints: [Int] = try? (container.decodeIfPresent([Int].self, forKey: .DA) ?? []) {
                // will pass here when `DA` is null or an array of ints
                DA = ACDeviceLastDataBody()
                DAasInts = ints
            } else {
                // null is already handled above
                DA = try container.decode(ACDeviceLastDataBody.self, forKey: .DA)
                DAasInts = []
            }
        }
    }
    

    您可能希望以不同的方式表示您的数据,例如从整数数组创建ACDeviceLastDataBody

    【讨论】:

    • 谢谢,我最终最终使用了这种方法并且它奏效了。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 2020-04-09
    • 1970-01-01
    • 2018-06-05
    相关资源
    最近更新 更多