首页 > 解决方案 > 如何使用 Codable 和 Hashable 在 Swift 中迭代 JSON 数组

问题描述

iOS 开发新手,在早期学习视图和动画方面取得了很大成功。但是,我无法弄清楚如何解析我的 JSON。我的主要目标是为诗句和章节设置参数以及返回字符串。我花了一天时间学习 Swift Dictionary Mapping,但认为 Codeable Mapping 是一种更简单的方法。

问题 1

从数据中获取 Bible.self 效果很好(我可以打印所有内容),但尝试解码 [Chapters].self 和 [Verses].self 会导致 nil,因此会出现 catch 错误。为什么会这样?

问题 2

Chapter 和 verse JSON 字段是字符串,这会在以后例如检索多节经文时引起问题吗?我知道有很多有用的 JSON 工具可以将这些字符串更改为 int。否则我希望'Hashable'可以工作。

问题 3

我最大的问题是我的 JSON 输出。我相信我需要一个循环内的循环(章节/诗句)。有没有更简单的方法来获取 JSON 中的某些字符串?

JSON 代码(片段):

    {
  "book": "Jude",
  "chapters": [
    {
      "chapter": "1",
      "verses": [
        {
          "verse": "1",
          "text": "Jude, the servant of Jesus Christ, and brother of James, to them that are sanctified by God the Father, and preserved in Jesus Christ, and called:"
        },
        {
          "verse": "2",
          "text": "Mercy unto you, and peace, and love, be multiplied."
        },
        {
          "verse": "3",
          "text": "Beloved, when I gave all diligence to write unto you of the common salvation, it was needful for me to write unto you, and exhort you that ye should earnestly contend for the faith which was once delivered unto the saints."
        }]}]} //it continues on...

我的结构

struct Bible : Codable, Hashable {
    let book : String
    let chapters : [Chapters]
}

struct Chapters : Codable, Hashable {
    let chapter : String
    let verses : [Verses]
}

struct Verses : Codable, Hashable {
    let verse : String
    let text : String
}

我的代码

func readJSONFromFile(fileName: String, getChapters: String, getVerses: String) -> String
{
    var JSONoutput: String = ""
    
    guard let path = Bundle.main.path(forResource: fileName, ofType: "json") else {return ""}

    let url = URL(fileURLWithPath: path)
    
    guard let data = try? Data(contentsOf: url, options: .mappedIfSafe) else {return ""}
                        
    
    do {
        let decoder = JSONDecoder()
        let bible = try decoder.decode(Bible.self, from: data)
        
        // the following give erros...
        // let chapters = try decoder.decode([Chapters].self, from: data)
        // let verses = try decoder.decode([Verses].self, from: data)
        
        // return:
        // JSONoutput = for x in BLANK {} ...
    }
    catch
    {
        print("error in parsing")
    }
    
    return JSONoutput
}

标签: arraysjsonswiftparsingcodable

解决方案


解码时返回的圣经对象将包含所有章节和经文,因此您无需解码其他任何内容。

您可以像这样更改解码功能

func readJSONFromFile(fileName: String) -> Bible? {    
    guard let path = Bundle.main.path(forResource: fileName, ofType: "json") else { return nil }
    let url = URL(fileURLWithPath: path)   
    guard let data = try? Data(contentsOf: url, options: .mappedIfSafe) else { return nil }
                            
    do {      
        return try JSONDecoder().decode(Bible.self, from: data)        
    } catch {
        print("error in parsing: \(error)")
        return nil 
    }
}

推荐阅读