Swift新手求助:SwiftUI中如何解析JSON对象数组?
嘿,别慌!作为Swift新手遇到这种解析崩溃太正常了,我来帮你搞定问题,顺便教你怎么用print调试,以后就能自己排查啦~
核心问题:JSON结构和你的结构体不匹配
你看,你的JSON里targets、benefits、steps都是包含name字段的对象数组,比如:
"targets": [ { "name": "Example Name" }, ... ]
但你在Obj结构体里把它们定义成了[String]类型,JSONDecoder根本不知道怎么把对象转成字符串,这就是解析失败导致崩溃的直接原因!
两种修正方案
方案1:定义子结构体(推荐,结构更清晰)
先为每个嵌套的对象定义对应的结构体,再修改Obj的属性类型:
// 对应JSON里的嵌套对象 struct Target: Codable, Hashable { var name: String } struct Benefit: Codable, Hashable { var name: String } struct Step: Codable, Hashable { var name: String } // 修改原Obj结构体的属性类型 struct Obj: Codable, Hashable { var id: Int var title: String var targets: [Target] var benefits: [Benefit] var steps: [Step] var videoURL: String }
如果之后需要提取纯字符串数组(比如所有target的name),可以用obj.targets.map { $0.name }快速转换。
方案2:自定义解码逻辑(直接转成字符串数组)
如果你不想额外定义子结构体,也可以让Obj实现自定义解码方法,直接把嵌套对象的name字段提取成字符串数组:
struct Obj: Codable, Hashable { var id: Int var title: String var targets: [String] var benefits: [String] var steps: [String] var videoURL: String enum CodingKeys: String, CodingKey { case id, title, targets, benefits, steps, videoURL } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 解码基础类型 id = try container.decode(Int.self, forKey: .id) title = try container.decode(String.self, forKey: .title) videoURL = try container.decode(String.self, forKey: .videoURL) // 自定义解码:把对象数组转成name字符串数组 let targetObjects = try container.decode([[String: String]].self, forKey: .targets) targets = targetObjects.compactMap { $0["name"] } let benefitObjects = try container.decode([[String: String]].self, forKey: .benefits) benefits = benefitObjects.compactMap { $0["name"] } let stepObjects = try container.decode([[String: String]].self, forKey: .steps) steps = stepObjects.compactMap { $0["name"] } } }
教你用print调试解码错误
你现在的decode函数用了try?,出错时只会直接触发fatalError,完全看不到具体错误原因,这对新手排查问题太不友好了!改成do-catch结构,打印详细错误信息,下次就能自己定位问题:
func decode<T: Decodable>(_ type:T.Type, from filename:String) -> T { guard let json = Bundle.main.url(forResource: filename, withExtension: nil) else { fatalError("Failed to locate \(filename) in app bundle.") } guard let jsonData = try? Data(contentsOf: json) else { fatalError("Failed to load \(filename) from app bundle.") } let decoder = JSONDecoder() do { let result = try decoder.decode(T.self, from: jsonData) return result } catch { // 打印详细错误信息,这就是调试的关键! print("解码错误详情:\(error)") fatalError("Failed to decode \(filename) from app bundle.") } }
这样下次再出错,你就能在控制台看到类似Expected to decode String but found a dictionary instead.的提示,一下子就知道哪里不匹配了~
内容的提问来源于stack exchange,提问作者Christopher Yeh
相关产品推荐
相关产品推荐

