Swift5中如何构造含指定结构双JSON数组的JSON对象?
问题:构建指定结构的JSON对象
初始需求与尝试
目标JSON结构如下(注:原示例中的=为笔误,标准JSON使用:):
{"config": [{"battery_state": "3.12","max_hum": "33","mode": "mode"}], "alarms": [{"1": "12345678"}, {"2": "22334455"}]}
尝试用NSMutableDictionary实现,但结果不符合预期:
let jsonConfigObject: NSMutableDictionary = NSMutableDictionary() jsonConfigObject.setValue("33" as String, forKey: "max_hum" as String) jsonConfigObject.setValue("3.12" as String, forKey: "battery_state" as String) jsonConfigObject.setValue("mode" as String, forKey: "mode" as String) let arrayConfig = [jsonConfigObject] var jsonAlarmObject: NSMutableDictionary = NSMutableDictionary() jsonAlarmObject.setValue("12345678" as String, forKey: "1" as String) var arrayAlarms = [jsonAlarmObject] jsonAlarmObject = NSMutableDictionary() jsonAlarmObject.setValue("22334455" as String, forKey: "2" as String) arrayAlarms.append(jsonAlarmObject) let array = [["config" : arrayConfig], ["alarms" : arrayAlarms]]
得到的错误结果:
[["config": [{"battery_state" = "3.12";"max_hum" = 33;mode = mode;}]], ["alarms": [{1 = 12345678;}, {2 = 22334455;}]]]
后续调整需求(编辑1)
改用Codable结构体尝试:
struct Config: Codable { let battery_state, max_hum, mode: String enum CodingKeys: String, CodingKey { case battery_state = "battery_state" case max_hum = "max_hum" case mode = "mode" } } var conf = Config(battery_state: "0", max_hum: "5", mode: "A") var alarms = [[String:String]]() alarms.append(["1":"123456"]) alarms.append(["2":"123456"]) alarms.append(["nb_alarms":String(Tag.sharedInstance.nb_alarms)])
得到的结果:
{"config":[{"current_hum":"56","period":"2","battery_level":"2.9"}],"alarms":[{"1":"123456"},{"2":"123456"},{"nb_alarms":"2"}]}
需要的目标结构:
{"config":[{"current_hum":"56","period":"2","battery_level":"2.9"}],"alarms":[{"1":"123456","2":"123456","nb_alarms":"2"}]}
解决方案
针对初始NSMutableDictionary的问题
核心错误是把最终对象构造成了数组包含两个字典,但目标是单个字典包含两个数组键值对。修改如下:
let jsonConfigObject: NSMutableDictionary = NSMutableDictionary() jsonConfigObject.setValue("33", forKey: "max_hum") jsonConfigObject.setValue("3.12", forKey: "battery_state") jsonConfigObject.setValue("mode", forKey: "mode") let arrayConfig = [jsonConfigObject] var jsonAlarmObject1: NSMutableDictionary = NSMutableDictionary() jsonAlarmObject1.setValue("12345678", forKey: "1") var jsonAlarmObject2: NSMutableDictionary = NSMutableDictionary() jsonAlarmObject2.setValue("22334455", forKey: "2") let arrayAlarms = [jsonAlarmObject1, jsonAlarmObject2] // 关键:构造单个顶级字典,而非数组包裹两个字典 let finalDict = ["config": arrayConfig, "alarms": arrayAlarms] // 转为标准JSON字符串输出 if let jsonData = try? JSONSerialization.data(withJSONObject: finalDict, options: .prettyPrinted), let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
输出会符合目标结构,JSONSerialization会生成标准:分隔的JSON,而非OC风格的=。
针对编辑1的Codable需求问题
需要alarms数组内只有一个字典,包含所有键值对,而非多个独立字典。修改alarms的构建方式:
struct Config: Codable { let current_hum, period, battery_level: String } var conf = Config(current_hum: "56", period: "2", battery_level: "2.9") // 构建单个字典,批量添加所有alarm键值 var alarmDict = [String: String]() alarmDict["1"] = "123456" alarmDict["2"] = "123456" alarmDict["nb_alarms"] = String(Tag.sharedInstance.nb_alarms) // 数组仅包含这一个字典 let alarms = [alarmDict] // 定义顶级结构统一管理 struct TopLevel: Codable { let config: [Config] let alarms: [[String: String]] } let topLevel = TopLevel(config: [conf], alarms: alarms) // 转为JSON字符串输出 if let jsonData = try? JSONEncoder().encode(topLevel), let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
后续添加大量键值时,直接往alarmDict内追加即可,无需重复创建新字典并append到数组。
内容的提问来源于stack exchange,提问作者tiamat
相关产品推荐
相关产品推荐

