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 可解码解析部分的主要内容,如果未能解决你的问题,请参考以下文章
用于解析平台 REST API (JSON) 并解码为结构的 Swift URLRequest