【问题标题】:Getting an error decoding JSON, Swift 4.2解码 JSON 时出错,Swift 4.2
【发布时间】:2019-03-28 21:40:42
【问题描述】:

在 swift 4.2 中解码 JSON 时出现错误

本应解码 Array 但找到了字典。

我的 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()
}

【问题讨论】:

    标签: ios json swift swift4.2 jsondecoder


    【解决方案1】:

    如果您查看返回的 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
    

    【讨论】:

    • 谢谢你的朋友。进行了更改,现在可以正常工作了。
    【解决方案2】:

    这应该是你的结构:

    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()
    

    希望这会有所帮助!

    【讨论】:

    • 我已经完成了更改,现在可以正常工作了,谢谢。
    • 也看看我对这个问题的编辑,我已经隐藏了你的 API 密钥,所以其他人无法使用它并更改了一些拼写和语法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    • 1970-01-01
    • 1970-01-01
    • 2019-07-28
    • 1970-01-01
    • 2018-07-30
    • 1970-01-01
    相关资源
    最近更新 更多