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

Swift 4解析嵌套JSON报错:圣经JSON转模型遇字段识别问题

Swift Codable解析圣经JSON数据时无法访问字段的问题

首先,你的核心问题在于模型定义和JSON结构不匹配,再加上错误处理太宽松(用try?吞掉了所有解码错误),导致你看不到真正的问题根源,误以为字段不存在。我帮你一步步梳理问题和修复方案:

一、Verse结构体的定义不符合JSON结构

你的JSON里每个经文对象是一个只有单个键值对的字典(比如{"1":"In the beginning God created the heaven and the earth."}),但你现在定义的Verse是把整个字典塞进verse属性里,这不仅不方便后续访问章节号和经文内容,还会导致解码逻辑混乱。

正确的做法是自定义Verse的解码逻辑,把动态的数字键作为number属性,对应的字符串值作为text属性:

struct Verse: Codable {
    let number: String
    let text: String
    
    // 自定义解码逻辑,处理动态键
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicCodingKey.self)
        // 每个经文对象只有一个键值对,直接取第一个键
        guard let key = container.allKeys.first else {
            throw DecodingError.dataCorrupted(.init(
                codingPath: decoder.codingPath,
                debugDescription: "经文对象没有找到有效键"
            ))
        }
        number = key.stringValue
        text = try container.decode(String.self, forKey: key)
    }
    
    // 用于处理动态字符串键的CodingKey
    private struct DynamicCodingKey: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int? { nil }
        init?(intValue: Int) { nil }
    }
}

二、错误处理太宽松,导致无法定位问题

你在解析时用了try?,这会把所有解码错误(比如字段不匹配、类型错误)都转换成nil,你完全看不到哪里出了问题。换成do-catch捕获错误,就能直接看到具体的错误信息:

func parse(json: Data) {
    let decoder = JSONDecoder()
    do {
        let jsonBible = try decoder.decode(Bible.self, from: json)
        bible = jsonBible
        
        // 安全访问book属性,避免强制解包崩溃
        myText = bible?.book
        print(myText ?? "获取书名失败")
        
        // 测试访问章节和经文
        if let firstChapter = bible?.chapters.first {
            print("第一章:\(firstChapter.chapter)")
            if let firstVerse = firstChapter.verses.first {
                print("第\(firstVerse.number)节:\(firstVerse.text)")
            }
        }
    } catch {
        print("解码错误详情:\(error)")
    }
}

三、移除多余的无效代码

你在parse函数里写了这两行完全多余的代码:

bible = jsonBible.self 
bible?.book = jsonBible.book 

jsonBible已经是完整的Bible实例,直接bible = jsonBible就足够了,后面的赋值操作没有任何意义,只会造成混淆。

四、避免强制解包的崩溃风险

你原来的myText = bible!.book用了强制解包!,如果解码失败bible是nil,这行代码会直接导致APP崩溃。改用可选访问或者空合运算符??来处理,保证代码的安全性。

额外优化:不要在主线程做同步网络请求

你用Data(contentsOf: url)是同步网络请求,会阻塞主线程,导致UI卡顿甚至被系统终止。建议换成URLSession的异步请求:

override func viewDidLoad() {
    super.viewDidLoad()
    let urlString = "https://raw.githubusercontent.com/aruljohn/Bible-kjv/master/Genesis.json"
    guard let url = URL(string: urlString) else {
        print("无效的URL地址")
        return
    }
    // 异步网络请求
    URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
        guard let data = data, error == nil else {
            print("网络请求失败:\(error?.localizedDescription ?? "未知错误")")
            return
        }
        // 回到主线程处理解析结果
        DispatchQueue.main.async {
            self?.parse(json: data)
        }
    }.resume()
}

做完这些修改后,你的模型就能正确解析JSON数据,也能正常访问book、chapters以及每一节经文的内容了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:15:06