从嵌套的 JSON 中检索数据

Posted

技术标签:

【中文标题】从嵌套的 JSON 中检索数据【英文标题】:Retrieving data from nested JSON 【发布时间】:2022-01-18 07:32:52 【问题描述】:

我正在努力理解如何从我的 JSON 文件中获取数据并使用它(例如在按下按钮时,它会更改标签文本或描述),尽管我已经阅读了无数的线程,但我仍然卡住了,但这里是我从这些文章和 *** 线程中尝试做的事情。

假设我有一个名为 Animals.json 的 json 文件:


"animal": [

    
       "name":"Cat",
       "image" : "cat.jpg",
       "category": "mammal"
    ,
   
    
        "name":"Eagle",
        "image" : "eagle.jpg",
        "category": "Bird",
    
 ]

我在一个名为 Animals.swift 的单独文件中创建了一个结构:

struct Animals: Codable 
var animal: [Animal]

然后是另一个名为 Animal.swift 的文件:

struct Animal : Codable 
var name: String
var image: String
var category: String   

这是我的 MainVC 中的代码:

import UIKit

class InstrumentsVC: UIViewController 
override func viewDidLoad() 
        super.viewDidLoad()
    
    if let localData = self.readLocalFile(forName: "Animals") 
        self.parse(jsonData: localData)
    
        
    



private func readLocalFile(forName name: String) -> Data? 
    do 
        if let bundlePath = Bundle.main.path(forResource: name,
                                             ofType: "json"),
            let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) 
            return jsonData
        
        
     catch 
        print(error)
    
    return nil


private func parse(jsonData: Data) 
    do 

        let decodedData = try JSONDecoder().decode(Animals.self,
                                                   from: jsonData)
        print("animal: ", decodedData.animal.first?.name ?? "")
        
     catch 
        print("decode error")
    


private func loadJson(fromURLString urlString: String,
                      completion: @escaping (Result<Data, Error>) -> Void) 
    if let url = URL(string: urlString) 
        let urlSession = URLSession(configuration: .default).dataTask(with: url)  (data, response, error) in
            if let error = error 
                completion(.failure(error))
            
            
            if let data = data 
                completion(.success(data))
            
        
        urlSession.resume()
    


@IBAction func nextCategory(_ sender: UIButton) 
    //I'll write a function that allows changing categories then loading an image that will update an outlet and labels



我还没有开始调用 loadJson 函数的部分,因为我打印了一个解码错误,而且我是 JSON 解码/解析的新手,我想知道哪里出了问题以及如何修复那。 这个想法是当我要按下一个按钮时,它会循环遍历我的 JSON 的“类别”部分(我还没有编写函数,但这应该不是问题),然后我有另一个按钮可以通过“名称”触发循环(这是一个简化的 JSON,因为会有很多来自同一类别的元素;它也不会是动物,而是一些与音乐相关的东西,我只是认为这样更容易理解用动物而不是放一些音乐理论的东西)。

现在我被打印在 readLocalFile 函数中的错误卡住了;然后从我读过的多篇文章中,我显然需要调用 loadJson 函数,但我还不太确定如何完成所有这些以获取每个元素的名称/图像/类别。 谢谢

【问题讨论】:

您的代码对我有用。您确定您在此处粘贴的代码与您的项目中的代码相同吗? 是的,除了其他插座和按钮外,它的代码完全相同 你的json不正确"category": "Bird",结尾应该有',' 感谢 Noor Ahmed,这是一个错字,我忘记在这里更正了,因为我在这篇文章中更改了我的 json 的实际内容,以便更容易理解,但我的 json 文件格式正确;但是,由于下面的答案,我找到了错误的原因:我的结构的名称与我的 JSON 略有不同。谢谢大家! 无关,但let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8)应该是let jsonData = try Data(contentsOfFile: bundlePath),不需要转换... 【参考方案1】:

我为你写了完整的答案..以此作为参考..祝你好运。

import UIKit

struct Animal : Codable 
    var name: String
    var image: String
    var category: String


struct Animals: Codable 
    var animal: [Animal]


class ViewController: UIViewController 
    override func viewDidLoad() 
        super.viewDidLoad()

        let data = Data.readJsonFile(withName: "Animals")
        
        do 
            let animalList = try JSONDecoder().decode(Animals.self, from: data!)
            for item in animalList.animal 
                print(item.name)
            
         catch 
            print("error")
        
    




extension Data 
    static func readJsonFile(withName name: String) -> Data? 
        do 
            if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
                let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) 
                return jsonData
            
         catch 
            print(error)
        
        return nil
    

【讨论】:

谢谢!但它仍然在控制台中打印错误并且不打印任何 item.name 上面的代码对我来说很好用。确保你添加了 Animals.json 文件。 是的,问题出在我的结构中,一些参数的名称与 json 文件的名称不完全相同(有几个错别字),但现在它可以工作了,非常感谢! print("error"):不,请不要那样做。而是:print("error: \(error)")。打印错误,它对失败的原因进行了有意义的描述,并让您知道如何修复它!【参考方案2】:

您共享的代码实际上正在运行。

如果您遇到解码错误。可能原因会是

    缺少任何空值或任何结构(动物)成员(名称、图像、类别)

所以你可以像可选的那样改变你的结构成员。因此,如果有任何失败情况,它可以保持零值。制作这样的结构

struct Animals: Codable 
var animal: [Animal]?


struct Animal : Codable 
var name: String?
var image: String?
var category: String?

访问值时不要忘记安全解包。

private func parse(jsonData: Data) 
    do 
        let decodedData = try JSONDecoder().decode(Animals.self, from: jsonData)
        print("animal: ", decodedData.animal?.first?.name ?? "")
     catch 
        print("decode error")
    

还有一个原因是类型转换错误。例如,成员(名称、图像、类别)在结构中被声明为字符串,但在 JSON 中,如果任何值是整数或不是字符串,则将是解码错误。你应该更正json

【讨论】:

就是这样!我的结构成员和我的 json 成员之间的不匹配,该死的错别字...... print("decode error"):不,请不要那样做。而是:print("decode error: \(error)")。打印错误,它对失败的原因进行了有意义的描述,并让您知道如何修复它!

以上是关于从嵌套的 JSON 中检索数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 laravel 6 中存储和检索嵌套的 JSON 数组

解析嵌套的 JSON 并将其保存到 SQLite 中,然后检索它

如何从在线 JSON API 中提取嵌套数据对象? [关闭]

如何在 React 中使用 useEffect hook 和 async/await 检索嵌套的 JSON 数据

通过 OPENJSON 检索 JSON 嵌套值

从 JSON 检索数据但无法从 JSONobject 访问 Arraylist