Расшифровка JSON для быстрой модели, а не корневого уровня - PullRequest
0 голосов
/ 01 января 2019

У меня есть следующая модель:

struct Article: Decodable {

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

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

}

JSON с URL выглядит следующим образом:

{
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]"
},

Все, что мне нужно, это значение в article ключ.Как я могу получить это используя Swift 4 JSONDecoder.

Я знаю, как это сделать, создав родительскую структуру, а затем создав свойство "article" внутри родительского объекта.Но как я могу сделать это без родительской структуры.

Ответы [ 3 ]

0 голосов
/ 01 января 2019

Используя только JSONDecoder, вы не можете декодировать без какой-либо внешней структуры, потому что ваш результат будет массив Article, который является внешней сущностью.Таким образом, простое определение 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, но другой код никогда не узнает (и никогда не узнает), что существует дополнительная структура Articles;он существует только временно внутри функции getArticles как своего рода локальный.Он не более нежелателен, чем любая другая локальная переменная, созданная временно в теле функции.

0 голосов
/ 01 января 2019

Рассмотрите возможность реструктуризации ваших данных.Вам необходимо структурировать модель данных так, чтобы она соответствовала структуре данных JSON.Вы можете включить только то, что вы хотите, но вы должны указать каждого родителя или уровень свойства, к которому вы хотите получить доступ.Возьмите следующий пример из API Википедии.Он выводит свойство title, которое находится на трех уровнях глубоко в структуре данных JSON.Он пропускает несколько свойств, как вы можете видеть из примера кода 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
0 голосов
/ 01 января 2019

Можно попробовать объединить JSONSerialization с JSONDecoder

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