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

时间:2019-01-01 01:32:28

标签: swift jsondecoder

我有以下模型:

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: "$70 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 $70 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 JSONDecoder获得它。

我知道如何创建父结构,然后在父内部创建“ articles”属性。但是,如果没有父结构,我该怎么办呢?

3 个答案:

答案 0 :(得分:2)

仅使用JSONDecoder,就无法在没有某种外部结构的情况下进行解码,因为您的结果将是Article的 array ,它是外部实体。因此,仅定义条文永远是不够的。

如果您不喜欢声明外部结构,而无需钻取到"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数组,但是其他代码从不知道(也永远无法发现)是否存在其他Articles结构;它仅在getArticles函数中作为一种本地临时存在。它不比在函数体内临时创建的任何其他局部变量更令人反感。

答案 1 :(得分:0)

您可以尝试将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)
}

答案 2 :(得分:0)

考虑重组您的数据。您需要构造数据模型以匹配JSON数据的数据结构。您可以仅包含所需的内容,但必须包含要访问的属性的每个父级或级别。从Wikipedia API中获取以下示例。它打印出了JSON数据结构中三个层次的title属性。从JSON示例代码中可以看出,它遗漏了几个属性,但它包含我需要访问所需属性的每个父级。

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