Получение ошибки декодирования JSON, Swift 4.2 - PullRequest
0 голосов
/ 29 марта 2019

Я получаю сообщение об ошибке при декодировании JSON в swift 4.2

Ожидается декодирование массива, но вместо этого найден словарь.

Моя модель JSON:

public struct NewsSource: Equatable, Decodable {

public let id: String?
public let name: String?
public let sourceDescription: String?
public let url: URL?

enum CodingKeys: String, CodingKey {
    case id
    case name
    case sourceDescription = "description"
    case url

}

public init(id: String,
            name: String,
            sourceDescription: String,
            url: URL,
            category: NewsCategory,
            language: NewsLanguage,
            country: NewsCountry) {
    self.id = id
    self.name = name
    self.sourceDescription = sourceDescription
    self.url = url
} }

Как получить JSON:

func fetchJSON() {

let urlString = "https://newsapi.org/v2/sources?apiKey=myAPIKey"

guard let url = URL(string: urlString) else { return }
    URLSession.shared.dataTask(with: url) { (data, _, err) in
        DispatchQueue.main.async {
            if let err = err {
                print("Failed to get data from url:", err)
                return
            }

            guard let data = data else { return }
            print(data)
            do {

                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase

                self.Sources = try decoder.decode([NewsSource].self, from: data)
                self.tableView.reloadData()

            } catch let jsonErr {
                print("Failed to decode:", jsonErr)
            }
        }
        }.resume()
}

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Если вы посмотрите на возвращаемый JSON, он выглядит так:

{
    "status": "ok",
    "sources": [{
        "id": "abc-news",
        "name": "ABC News",
        "description": "Your trusted source for breaking news, analysis, exclusive interviews, headlines, and videos at ABCNews.com.",
        "url": "https://abcnews.go.com",
        "category": "general",
        "language": "en",
        "country": "us"
    }, {
        "id": "abc-news-au",
        "name": "ABC News (AU)",
        "description": "Australia's most trusted source of local, national and world news. Comprehensive, independent, in-depth analysis, the latest business, sport, weather and more.",
        "url": "http://www.abc.net.au/news",
        "category": "general",
        "language": "en",
        "country": "au"
    }, 
    ...

Хотя существует массив источников, этот массив не является корневым.Корнем JSON является объект со строкой status и массивом sources.Вот почему декодер не работает.

Вам необходимо определить дополнительную структуру для обработки этого:

struct NewsResult {
    let status: String
    let sources: [NewsSource]
}

Затем вы декодируете этот объект:

let sourceResult = try decoder.decode(NewsResult.self, from: data)
self.sources = sourceResult.sources
0 голосов
/ 29 марта 2019

Это должна быть ваша структура:

struct NewsSource: Codable {
    let status: String
    let sources: [NewsSource]
}

public struct NewsSource: Equatable, Decodable {

public let id: String?
public let name: String?
public let sourceDescription: String?
public let url: URL?

enum CodingKeys: String, CodingKey {
    case id
    case name
    case sourceDescription = "description"
    case url

}

public init(id: String,
            name: String,
            sourceDescription: String,
            url: URL,
            category: NewsCategory,
            language: NewsLanguage,
            country: NewsCountry) {
    self.id = id
    self.name = name
    self.sourceDescription = sourceDescription
    self.url = url
} }

struct Source: Codable {
    let id, name, description: String
    let url: String
    let category: Category
    let language, country: String
}

enum Category: String, Codable {
    case business = "business"
    case entertainment = "entertainment"
    case general = "general"
    case health = "health"
    case science = "science"
    case sports = "sports"
    case technology = "technology"
}

А затем расшифровать его:

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let newsSource = try? decoder.decode(NewsSource.self, from: data)
self.Sources = newsSource.sources
self.tableView.reloadData()

Надеюсь, это поможет!

...