Swift 4 解析 1+n 数量的 json 数字键

Posted

技术标签:

【中文标题】Swift 4 解析 1+n 数量的 json 数字键【英文标题】:Swift 4 parsing json numeric keys with 1+n amount 【发布时间】:2018-07-10 18:41:37 【问题描述】:

我仍在学习这个 Codable/Decodable Swift 4 中的新功能,用于 JSON 解析。

我能够构建一个结构并获取温度键,但 Pump 和其他类似的项目是可以是 1 到 n 的数字字符串。将它们解析为数组或字典的最佳方法是什么。我会假设一个 for 循环?

 public struct ServerReponse: Codable 
    let temperature: Temperature
    let circuit: Circuit 
 

public struct Circuit: Codable 
    let number: Int
    let numberStr: String
    let name: String
    let circuitFunction: String
    let status: Int
    let freeze: Int
    let delay: Int
    let friendlyName: String
    let light: Light?


public struct Light: Codable 
    let pump: Int
    let position: Int
    let colorStr: String
    let color: Int
    let colorSet: Int
    let colorSetStr: String
    let prevColor: Int
    let prevColorStr: String
    let colorSwimDelay: Int
    let mode: Int
    let modeStr: String


public struct Temperature : Codable 
    let poolTemp: Int
    let airTemp: Int
    let poolSetPoint: Int
    let heaterActive: Int
    
...
let poolData = try? JSONDecoder().decode(ServerReponse.self, from: data)
print(poolData?.temperature)

我在解析下一部分“电路”时遇到问题,其中可能有 1 到多个数字键,然后电路结构本身位于每个数字键下方。

这是我正在使用的一些 JSON...


"temperature": 
    "poolTemp": 85,
    "spaTemp": 85,
    "airTemp": 75,
    "solarTemp": 0,
    "freeze": 0,
    "poolSetPoint": 82,
    "poolHeatMode": 1,
    "poolHeatModeStr": "Heater",
    "spaSetPoint": 80,
    "spaManualHeatMode": "Off",
    "spaHeatMode": 0,
    "spaHeatModeStr": "OFF",
    "heaterActive": 0
,
"circuit": 
        "1": 
            "number": 1,
            "numberStr": "circuit1",
            "name": "SPA",
            "circuitFunction": "Spa",
            "status": 0,
            "freeze": 0,
            "macro": 0,
            "delay": 0,
            "friendlyName": "SPA"
        ,
        "2": 
            "number": 2,
            "numberStr": "circuit2",
            "name": "POOL LIGHT",
            "circuitFunction": "Intellibrite",
            "status": 0,
            "freeze": 0,
            "macro": 0,
            "delay": 0,
            "friendlyName": "POOL LIGHT",
            "light": 
                "position": 1,
                "colorStr": "off",
                "color": 0,
                "colorSet": 12,
                "colorSetStr": "Magenta",
                "prevColor": 0,
                "prevColorStr": "White",
                "colorSwimDelay": 5,
                "mode": 0,
                "modeStr": "Off"
            
        ,
        "3": 
            "number": 3,
            "numberStr": "circuit3",
            "name": "AUX 2",
            "circuitFunction": "Generic",
            "status": 1,
            "freeze": 0,
            "macro": 0,
            "delay": 0,
            "friendlyName": "OUTLET - PINE TREE"
        ,
        "4": 
            "number": 4,
            "numberStr": "circuit4",
            "name": "AUX 3",
            "circuitFunction": "Generic",
            "status": 1,
            "freeze": 0,
            "macro": 0,
            "delay": 0,
            "friendlyName": "OUTLET - FOUNTAIN"
        ,
        "5": 
            "number": 5,
            "numberStr": "circuit5",
            "name": "AUX 4",
            "circuitFunction": "Generic",
            "status": 0,
            "freeze": 0,
            "macro": 0,
            "delay": 0,
            "friendlyName": "AUX 4"
        ,
        "6": 
            "number": 6,
            "numberStr": "circuit6",
            "name": "POOL",
            "circuitFunction": "Pool",
            "status": 1,
            "freeze": 1,
            "macro": 0,
            "delay": 0,
            "friendlyName": "POOL"
        ,
      .... more keys ....

【问题讨论】:

【参考方案1】:

circuit 的值是一个字典。

如果您需要通过数字快速访问,请将对象解码为[String:Circuit]

public struct ServerReponse: Codable 
   let temperature: Temperature
   let circuit: [String:Circuit] 

如果数组更合适,请编写一个自定义初始化程序,该初始化程序另外将值映射到数组。

public struct ServerReponse: Codable 
    let temperature: Temperature
    let circuits: [Circuit]

    private enum CodingKeys: String, CodingKey  case temperature, circuits = "circuit"

    public init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        temperature = try container.decode(Temperature.self, forKey: .temperature)
        let circuitData = try container.decode([String:Circuit].self, forKey: .circuits)
        circuits = Array(circuitData.values).sorted(by: $0.number < $1.number)
    

【讨论】:

【参考方案2】:
var json = """

  "temperature": 
    "poolTemp" : 85,
    "spaTemp"  : 85,
    "airTemp"  : 75
  ,
  "circuit": 
    "1": 
      "number": 1,
      "numberStr": "circuit1",
      "name": "SPA"
    ,
    "2": 
      "number": 2,
      "numberStr": "circuit2",
      "name": "POOL LIGHT"
    
  

""".data(using: .utf8)!

struct Weather :Codable 
    let temperature:Temperature
    let circuit:Circuit

struct Temperature :Codable
    let poolTemp:Int 
    let spaTemp:Int 
    let airTemp:Int

struct Circuit:Codable 
  let one:Circuits 
  let two:Circuits
  enum CodingKeys:String,CodingKey 
      case one = "1" 
      case two = "2"
  

struct Circuits: Codable 
    let number: Int 
    let numberStr : String
    let name: String

do 
let decoder = try JSONDecoder().decode(Weather.self , from: json) 
 print(decoder)
catch 
    print("Error decoding Data")

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于Swift 4 解析 1+n 数量的 json 数字键的主要内容,如果未能解决你的问题,请参考以下文章

JSON .count 数组在 Swift 4 中总是返回 0

解析 JSON 数据时出错(Swift 4 Playground)

JSON解析错误Swift 3

解析 JSON Swift 4

JSON 解析 Swift 4

用 Codable,swift 4 解析 JSON