You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何解码根层级为动态key的JSON并在SwiftUI中遍历?

解码失败问题解决

你遇到的解码报错核心原因是JSONDecoder默认的日期解码策略是将日期解析为UNIX时间戳(Double类型),但Hue Bridge返回的lastinstall是ISO8601格式的字符串,只需要在解码前配置解码器的日期策略即可:

let decoder = JSONDecoder()
// 适配Hue返回的ISO8601格式日期
decoder.dateDecodingStrategy = .iso8601
// 如果系统自带的iso8601策略不匹配(比如部分旧版Hue固件日期不带时区),可以自定义日期格式:
// let dateFormatter = DateFormatter()
// dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
// dateFormatter.locale = Locale(identifier: "en_US_POSIX")
// decoder.dateDecodingStrategy = .formatted(dateFormatter)
let lights = try decoder.decode([String: LightInfo].self, from: data)

另外要注意如果JSON中部分字段可能缺失,建议把对应的属性声明为可选(比如var reachable: Bool?),避免单个字段缺失导致整个解码失败。

字典遍历优化方案

你当前的遍历写法可以简化,同时避免强制解包的风险,推荐两种更安全的写法:

方案1:转键值对数组遍历

直接将字典转成[(key: String, value: LightInfo)]类型的数组,用key作为唯一标识即可:

struct LightsView: View {
    @Binding var lights: [String:LightInfo]
    
    var body: some View {
        VStack {
            ForEach(Array(lights), id: \.key) { lightId, lightInfo in
                LightView(lightInfo: lightInfo, lightId: Int(lightId) ?? 0)
            }
        }
    }
}

这种写法更直观,不需要额外处理keys枚举,也避免了强制解包lights["\(value)"]!的崩溃风险。

方案2:预处理成模型数组

如果不需要用到灯光ID的字符串key,可以在解码完成后直接把字典转成包含ID的模型数组,后续使用更方便:

// 提前定义带ID的模型
struct LightItem: Identifiable {
    let id: Int
    let info: LightInfo
}
// 解码后转换
let lightDict = try decoder.decode([String: LightInfo].self, from: data)
let lights = lightDict.compactMap { key, info in
    guard let id = Int(key) else { return nil }
    return LightItem(id: id, info: info)
}
// 后续View中可以直接遍历
ForEach(lights) { light in
    LightView(lightInfo: light.info, lightId: light.id)
}

这种写法符合SwiftUI对于Identifiable类型的遍历规范,代码更简洁。

内容的提问来源于stack exchange,提问作者Slawa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 20:06:05