简体   繁体   English

Swift JSON的可解码解析部分

[英]Swift Decodable parse part of JSON

I'm trying to parse a json that looks like this using decodable:我正在尝试使用 decodable 解析看起来像这样的 json:

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

My problem is that I don't want to make a class that has a count property just to be able to use the decoder.我的问题是我不想制作一个具有计数属性的 class 只是为了能够使用解码器。 I want to parse only the results part I don't care about the count.我只想解析我不关心计数的结果部分。

So my question is, can decodable.decode somehow only parse a part of the result json. I mean a certain key path instead of the whole json?所以我的问题是,decodable.decode 能否以某种方式只解析结果 json 的一部分。我的意思是某个关键路径而不是整个 json? And I want to do it using Decodable.我想使用 Decodable 来做到这一点。

In a nutshell I don't want this:简而言之,我不想要这个:

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

What I would Imagine is to have this:我想象的是拥有这个:

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

Thanks谢谢

let me see what I can suggest:让我看看我能提出什么建议:

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)
   }
}

See this documentation for more insight请参阅此文档以获取更多信息

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

Hope it helps your project!希望对你的项目有所帮助!

You probably is looking for JSONSerialization class. This is an example how it works:您可能正在寻找JSONSerialization class。这是它如何工作的示例:

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

You can define a generic wrapper for once and use everywhere.您可以一次定义一个通用包装器并在任何地方使用。

It will work as a generic wrapper for results key only.它将仅用作结果键的通用包装器。

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

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

Extend JSONDecoder to get results output.扩展 JSONDecoder 得到结果 output。

  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
        }
    }

And use like this并像这样使用

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)!))

See how it makes everything more complex.看看它是如何让一切变得更复杂的。 BETTER USE IncidentWrapper!!!更好地使用事件包装器!!!

You only need to use the keys you care about.您只需要使用您关心的密钥。 Just leave off the count.别管数了。 Don't make it part of your struct.不要让它成为你的结构的一部分。

You will only get errors if you can't find a key in the json that you are expecting in the struct.如果您无法在结构中期望的 json 中找到键,您只会收到错误。 You can avoid this too, though, if you make it an optional in the struct.不过,如果在结构中将其设为可选,也可以避免这种情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM