JSON 可解码 - 按键搜索

Posted

技术标签:

【中文标题】JSON 可解码 - 按键搜索【英文标题】:JSON Decodable - search by key 【发布时间】:2018-05-12 07:14:01 【问题描述】:

我正在尝试编写一些代码来通过密钥从我的 JSON 中获取信息。

JSON 看起来像:


  "Test Name": 
    "schede": 
      "info_01": "Info 01",
      "info_02": "Info 02",
      "info_03": "Info 03",
      "info_04": "Info 04",
      "info_05": "Info 05"
      ,
    "Info" : "info"
  

我希望在应用程序启动时下载 JSON。 JSON已解码,我想创建一个传递密钥的函数,它将打印我需要的所有信息,例如 schede.info_01 或 JSON 上的信息字符串。 这就像一个可解码的 JSON

例如,我的 JSON 中的键是:“测试名称” 然后,如果您在函数中传递字符串“测试名称”,它将打印每个结果,例如:“测试名称”.schede.info_01 等

我从一个链接获取 JSON

【问题讨论】:

您确定要为此使用Decodable 吗?仅使用 JSONSerialization 将 JSON 转换为 Dictionary 会更容易用于此类功能。 我需要从密钥中获取单个信息,而不是直接获取整个 json 我的意思是说,将 JSON 转换为字典(使用 JSONSerialization)而不是结构/类(使用 Decodable)会给你更多的灵活性来编写一个允许你打印的函数以您想要的方式获取数据。 另外,为了清楚起见,您能否扩展预期的输出并编写一个完整的示例 这是 json 的一部分,你能用所有的回答来更新你的问题,以知道你是否有字典数组 【参考方案1】:

首先从 json 创建数据模型:

struct MyData: Codable 
    let testName: TestName

    enum CodingKeys: String, CodingKey 
        case testName = "Test Name"
    


struct TestName: Codable 
    let schede: [String: String]
    let info: String

    enum CodingKeys: String, CodingKey 
        case schede
        case info = "Info"
    

如果您不确定 JSON 是否始终具有特定值,则可以将属性设为可选。

然后创建一个函数来获取数据并解析它:

func getData(url: URL, completion: @escaping (_ data: MyData?, _ error: Error?) -> ()) 
    let task = URLSession.shared.dataTask(with: url)  (data, response, error) in
        guard let receivedData = data else 
            completion(nil, error)
            return
        

        do 
            // Check if there is a valid json object and parse it with JSONDecoder
            let object = try JSONDecoder().decode(MyData.self, from: receivedData)
            completion(object, nil)
         catch 
            completion(nil, error)
        
    
    task.resume()

然后调用你的函数:

    getData(url: URL(string: "https://yourexampleurl.com/myData")!)  (data, error) in
        // if you want to use the received data in the UI
        // you need to dispatch it back to the main thread
        // because dataTask executes it not on the main thread (by default)
        DispatchQueue.main.async 
            if let info1 = data?.testName.schede["info_01"] 
                print("received mt info: \(info1)")
             else 
                let errorMessage = error?.localizedDescription ?? "unknown error"
                print("error occured: \(errorMessage)")
            
        
    

因为您将 json 结构映射到 Swift 对象,您可以使用点运算符访问您的数据:

let info1 = data.testName.schede["info_01"]

您也可以一路为Schede 对象创建模型,然后您可以访问类似这样的值,而不是将其解析为字典:

let info1 = data.testName.schede.info1

【讨论】:

请在使用Codable 时尽可能多地声明自定义结构中的属性-可选-在大多数情况下,您知道服务器将发送什么-并处理catch 块中的(设计)错误。 try?JSONDecoder 非常糟糕。 @vadian 我编辑了我的答案。我完全同意docatch 的观点。关于模型中的选项,我同意“尽可能”的观点。 我也是这样做的,但是我需要json只下载一次,我可以在所有文件中调用get result函数 如果您只需要下载一次数据,那么就这样做 - 调用一次函数,存储检索到的数据并使其可供其他对象访问。

以上是关于JSON 可解码 - 按键搜索的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AlamoFire 搜索 JSON API 和解码数组

使用可解码和 JSON

使用可解码返回空模型解析 JSON

使用可选值 Swift 4 解码嵌套 JSON

JSON 的 Swift 可解码解析部分

带有可配置键的 Swift 4 JSON 解码