将 JSON 解码为 Swift 模型而非根级别

Decoding JSON to Swift Model Not Root Level

我有以下型号:

struct Article: Decodable {

    let title: String
    let description: String
    let imageURL: String

    private enum CodingKeys: String, CodingKey {
        case title
        case description
        case imageURL = "urlToImage"
    }

}

来自URL的JSON是这样的:

{
  status: "ok",
  totalResults: 70,
  articles: [
    {
      source: {
        id: null,
        name: "Oilprice.com"
      },
      author: "Tim Daiss",
      title: " Oil Could Be Right Around The Corner | OilPrice.com - OilPrice.com",
      description: "A recent Bloomberg survey of oil analysts suggests that many believe oil could hit  per barrel in 2019, but are they just downplaying the bearish signals?",
      url: "https://oilprice.com/Energy/Crude-Oil/70-Oil-Could-Be-Right-Around-The-Corner.html",
      urlToImage: "https://d32r1sh890xpii.cloudfront.net/article/718x300/d7b8868e80d766d6a5d401219c65d6a0.jpg",
      publishedAt: "2019-01-01T00:00:08Z",
      content: "Oil markets have always been cyclical, and now even more so with advanced electronic trading, more speculation (which often results in wider oil price swings) and more producers, including the resurgence of U.S. oil production, now reaching over 11 million ba… [+4696 chars]"
    },
    {
      source: {
        id: "cnbc",
        name: "CNBC"
      },
      author: "Jordan Novet",
      title: "Activision Blizzard plans to fire its CFO for an unspecified cause - CNBC",
      description: "Shares of gaming company Activision Blizzard moved lower Monday after it announced plans to let go of its chief financial officer.",
      url: "https://www.cnbc.com/2018/12/31/activision-blizzard-plans-to-fire-its-cfo-for-an-unspecified-cause.html",
      urlToImage: "https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2012/08/02/48465125-activision-200.1910x1000.jpg",
      publishedAt: "2018-12-31T23:18:17Z",
      content: "Activision Blizzard shares moved down 1 percent in after-hours trading on Monday after the company said that it has informed its chief financial officer, Spencer Neumann, that it plans to let him go. For now he has been placed on a paid leave of absence. div … [+950 chars]"
    }
  ]
}

我只想要 articles 键中的值。如何使用 Swift 4 JSON 解码器获取它。

我知道如何通过创建父结构然后在父结构中创建 "articles" 属性 来实现。但是如果没有父结构我怎么能这样做呢。

您可以尝试将 JSONSerializationJSONDecoder

结合使用
do
{
    let tr = try JSONSerialization.jsonObject(with:data, options:[]) as! [String:Any] 
    guard let content =  tr["articles"] else { return }
    let articlesData = try JSONSerialization.data(withJSONObject:content, options: [])
    let res = try JSONDecoder().decode([Article].self, from: articlesData) 
    print(res) 
}
catch 
{
    print(error)
}

单独使用JSON解码器,如果没有某种外部结构,您将无法解码,因为您的结果将是 Article 的 array,这是一个外部结构实体。因此仅仅定义 Article 是不够的。

如果您不喜欢声明一个外部结构,除了向下钻取到 "articles" 键之外,您不需要任何其他目的,只需临时声明它即可轻松解决 在您向下钻取到 "articles" 键的有限范围内。因此,您的程序的其余部分保留在 Article 结构中,但外部结构不存在。

例如:

struct Article: Decodable {
    // ... your code here ...
}
func getArticles(_ d:Data) -> [Article] {
    struct Articles: Decodable { // this struct is temporary
        let articles:[Article]
    }
    return try! JSONDecoder().decode(Articles.self, from: d).articles
}

其他代码现在可以看到 Article 结构并可以调用 getArticles 来解析 JSON 并接收 Article 数组,但其他代码永远不知道(也永远无法发现)存在额外的文章结构;它仅作为一种局部函数暂时存在于 getArticles 函数中。它并不比在函数体内临时创建的任何其他局部变量更令人反感。

考虑重组您的数据。您需要构建数据模型以匹配 JSON 数据的数据结构。您可以只包含您想要的内容,但您必须包含您想要访问的每个 parent 或 属性(s) 级别。以维基百科 API 中的以下示例为例。它打印出 属性 的标题 属性 ,它深入 JSON 数据结构的三个层次。正如您从 JSON 示例代码中可以看出的那样,它省略了几个属性,但它包含了每个 parent 我需要访问我想要的 属性(s)。

import UIKit

struct Item: Decodable {
    var title: String
}

struct Search: Decodable {
    var search: [Item]
}

struct Result: Decodable {
    var query: Search
}

func getSearchResults(){
    let url = URL(string: "https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=swift%204&utf8=&format=json")!

    URLSession.shared.dataTask(with: url) { (data, response, error) in
    if let urlResponse = response as? HTTPURLResponse, urlResponse.statusCode == 200 {
        guard let data = data else { return }
        do {
            let results = try JSONDecoder().decode(Result.self, from: data)
            for item in results.query.search {
                print(item.title)
            }
        } catch let error as NSError {
            print("error: \(error)")
        }
    }
}.resume()
}
getSearchResults()

JSON 示例:

{
"batchcomplete": "",
"continue": {
    "sroffset": 10,
    "continue": "-||"
},
"query": {
    "searchinfo": {
        "totalhits": 30349
    },
    "search": [
        {
            "ns": 0,
            "title": "Swift",
            "pageid": 219023,
            "size": 13896,
            "wordcount": 1496,
            "snippet": "The <span class=\"searchmatch\">swifts</span> are a family, Apodidae, of highly aerial birds. They are superficially similar to swallows, but are not closely related to any passerine species",
            "timestamp": "2018-12-28T21:29:44Z"
        },
        {
            "ns": 0,
            "title": "Swift (programming language)",
            "pageid": 42946389,
            "size": 49365,
            "wordcount": 5244,
            "snippet": "2015. <span class=\"searchmatch\">Swift</span> 3.0 was released on September 13, 2016. <span class=\"searchmatch\">Swift</span> <span class=\"searchmatch\">4</span>.0 was released on September 19, 2017. <span class=\"searchmatch\">Swift</span> <span class=\"searchmatch\">4</span>.1 was released on March 29, 2018. <span class=\"searchmatch\">Swift</span> won first",
            "timestamp": "2018-12-19T02:52:33Z"
        },
        {
            "ns": 0,
            "title": "Taylor Swift",
            "pageid": 5422144,
            "size": 237225,
            "wordcount": 18505,
            "snippet": "Taylor Alison <span class=\"searchmatch\">Swift</span> (born December 13, 1989) is an American singer-songwriter. One of the world's leading contemporary recording artists, she is known",
            "timestamp": "2018-12-26T21:55:51Z"
        },

这是打印的输出:

//Swift
//Swift (programming language)
//Taylor Swift