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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 15:57:26