JSON 的 Swift 可解码解析部分

Posted

技术标签:

【中文标题】JSON 的 Swift 可解码解析部分【英文标题】:Swift Decodable parse part of JSON 【发布时间】:2020-04-13 22:44:55 【问题描述】:

我正在尝试使用 decodedable 解析一个看起来像这样的 json:

    
    "count": 1,
    "results": [
        
            "title": 1,
            "content": "Bla"
         ]
    

我的问题是我不想创建一个具有计数属性的类,只是为了能够使用解码器。我只想解析我不关心计数的结果部分。

所以我的问题是, decodedable.decode 能否以某种方式仅解析结果 json 的一部分。我的意思是某个关键路径而不是整个 json ?我想使用 Decodable 来做到这一点。

简而言之,我不想要这个:

class IncidentWrapper: Codable
    var count: Int
    var incident: [Incident]

我想拥有这个:

decodable.decode([Incident].self, from: response.data, forKey: "results")

谢谢

【问题讨论】:

您可以编写一个自定义解码器以符合Decodable,但在我看来,免费获取解码代码足以弥补声明一个小结构的需要。您甚至不必将该结构暴露给应用程序的其余部分;您可以简单地从网络获取操作中公开 root.results 而不是 root 老实说,制作包装结构通常更容易。您不想这样做有什么特别的原因吗? 【参考方案1】:

让我看看我能提出什么建议:

struct Result: Codeable 
   var id: Int
   var message: String
   var color: String
   var type: String

   enum CodingKeys: String, CodingKey 
      case results
   

   enum NestedResultKeys: String, CodingKey 
      case id, message, color, type
   


extension Result: Decodable 
   init(from decoder: Decoder) throws 
      let result = try decoder.container(keyedBy: CodingKeys.self)

      let nestedResult = try result.nestedContainer(keyedBy: NestedResultKeys.self, forKey: .result)
      id = try nestedResult.decode(Int.self, forKey: .id)
      message = try nestedResult.decode(String.self, forKey: .message)
      color = try nestedResult.decode(String.self, forKey: .color)
      type = try nestedResult.decode(String.self, forKey: .id)
   

查看此文档了解更多信息

https://developer.apple.com/documentation/swift/swift_standard_library/encoding_decoding_and_serialization

希望它对您的项目有所帮助!

【讨论】:

【参考方案2】:

您可能正在寻找JSONSerialization 类。这是一个如何工作的示例:

    if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] 
        if let results = json["results"] as? [Incident] 
            print(results.count)
        
    

【讨论】:

谢谢,但我正在寻找使用可解码的解决方案 Decodable 仅适用于结构或类。如果你想手动解码数据,你应该使用 JSONSerialization 来代替【参考方案3】:

您可以定义一个通用包装器一次并在任何地方使用。

它将仅用作结果键的通用包装器。

protocol ResultsDecodable: Decodable
    associatedtype T: Decodable
    var results: [T] get


struct Result<Element: Decodable>: ResultsDecodable
    typealias T = Element
    var results: [Element]

扩展 JSONDecoder 以获得结果输出。

  extension JSONDecoder 
        func resultDecode<T>(_ type: Result<T>.Type, from data: Data) throws -> [T] where T : Decodable
            let model = try! decode(type, from: data)
            return model.results
        
    

并像这样使用

var str = #""count": 1,"results": ["title": 1,"content": "Bla", "title": 2,"content": "Bla" ]"#

class Incident: Decodable
    let title: Int
    let content: String


let indicents = (try! JSONDecoder().resultDecode(Result<Incident>.self, from: str.data(using: .utf8)!))

看看它如何让一切变得更加复杂。更好地使用 IncidentWrapper!!!

【讨论】:

这是迄今为止我在 *** 上得到的最有说服力的答案?谢谢你,IncidentWrapper 它是?【参考方案4】:

您只需要使用您关心的密钥。就别算了。不要让它成为你的结构的一部分。

只有当你在 json 中找不到你期望在结构中的键时,你才会得到错误。不过,如果您在结构中将其设为可选项,您也可以避免这种情况。

【讨论】:

但这会让我有一个包装类,它只会有结​​果。我想用 results 属性创建一个没有父空类的可解码类

以上是关于JSON 的 Swift 可解码解析部分的主要内容,如果未能解决你的问题,请参考以下文章

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

用于解析平台 REST API (JSON) 并解码为结构的 Swift URLRequest

如何在 Swift 中使用可解码?

在swift iOS中使用JSON解码器解析本地Json

在 Swift 中使用 JSON 解码器难以解析 JSON 中的整数值

我如何使用解码器在swift 4中解析tableview中的json数组