Всплывает ошибка декодирования JSON, не знаю, что еще попробовать

#ios #json #swift

#iOS #json #swift

Вопрос:

ребята, я был бы очень признателен за помощь в декодировании JSON. Я пытаюсь получить API по этой ссылке: http://newsapi.org/v2/top-headlines?apiKey=a16b15f863454928804e218705d0f019 amp;country=сша Возможно, я допустил несколько действительно любительских ошибок. При первой загрузке проблема здесь. Обращаюсь за помощью!

Вот мой DataManager

 protocol NewsManagerDelegate {
    func didUpdateNews(news: NewsModel)
}
import Foundation

struct NewsManager{
    
    
    var delegate: NewsManagerDelegate?
    
    let url = "https://newsapi.org/v2/top-headlines?apiKey=a16b15f863454928804e218705d0f019"
    
    
    func fetchNews(_ countryName: String){
        let newsUrlString = "(url) amp;country=(countryName)"
        performRequest(newsUrlString)
    }
    
    func performRequest(_ urlString: String){
        if let url = URL(string: urlString){
            let session = URLSession(configuration: .default)
            let task = session.dataTask(with: url) { (data, response, error) in
                if error != nil {
                    print("networking error (error!)")
                    return
                }
                
                if let safeData = data{
                    if let news = parseJSON(safeData){
                        delegate?.didUpdateNews(news: news)
                }
            }
            }
            task.resume()
        }
    }
    
    func parseJSON(_ newsData: Data) -> NewsModel?{
        do{
            let decodedData = try JSONDecoder().decode(NewsData.self, from: newsData)
            let sourceName = decodedData.articles[5].source.name
            let titleName = decodedData.articles[5].title
            let linkToImage = decodedData.articles[5].urlToImage
            let news = NewsModel(sourceName: sourceName, titleName: titleName, linkToImage: linkToImage ) 
            return news
        }catch{
            print(error)
            return nil
        }
        
    }
    
    
    
    
    
}
 

и мои данные

 import Foundation

struct NewsData: Codable {
    let totalResults: Int
    let articles: [Articles]

}

struct Articles: Codable{
    let author: String?
    let title: String
    let description: String
    let urlToImage: String
    let source: Source
    
}

struct Source: Codable{
    let name: String
}
 

Я получаю эту ошибку

 valueNotFound(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "articles", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "description", intValue: nil)], debugDescription: "Expected String value but found null instead.", underlyingError: nil))
 

Я попытался сделать некоторые константы необязательными, но после этого информация вообще не отображалась.

Комментарии:

1. Вы можете просмотреть ошибку журнала и попытаться прочитать ее, в ней указан весь путь к ключу, вызывающему проблему

2. Поскольку вы, похоже, получаете данные, но у вас возникают проблемы с их анализом, вам следует попытаться уменьшить область видимости. Распечатайте данные JSON и сведите их к одному примеру статьи, который не удалось проанализировать. Опубликуйте его в виде строки (скорее всего, в «»»-кавычках, чтобы его было легче читать) и предоставьте полученное сообщение об ошибке. Таким образом, у людей будет меньше проблем с обнаружением ошибки.

Ответ №1:

Я бы просто изменил имя свойства на articleDescription и сделал его необязательным. Если вы хотите проанализировать publishedAt дату, все, что вам нужно, это установить dateDecodingStrategy для свойства decoder .iso8601 значение . Кроме того, вы неправильно создаете свой URL-адрес. Вы всегда должны использовать URLComponents при составлении своего URL-адреса и изменять типы свойств URL-адресов с String на URL :

 struct Root: Codable {
    let status: String
    let totalResults: Int
    let articles: [Article]
}
 

 struct Article: Codable {
    let source: Source
    let author: String?
    let title: String
    let articleDescription: String?
    let url, urlToImage: URL
    let publishedAt: Date
    let content: String?
    enum CodingKeys: String, CodingKey {
        case source, author, title, articleDescription = "description", url, urlToImage, publishedAt, content
    }
}
 

 struct Source: Codable {
    let id: String?
    let name: String
}
 

Тестирование игровой площадки:

 func fetchNews(_ countryCode: String) {
    var urlComponents = URLComponents()
    urlComponents.scheme = "https"
    urlComponents.host = "newsapi.org"
    urlComponents.path = "/v2/top-headlines"
    urlComponents.queryItems = [.init(name: "apiKey", value: "a16b15f863454928804e218705d0f019"),
                                .init(name:"country", value: countryCode)]
    if let url = urlComponents.url {
        performRequest(url)
    }
}
func performRequest(_ url: URL) {
    URLSession.shared.dataTask(with: url) { data, response, error in
        guard let data = data else {
            print("networking error", error ?? "nil")
            return
        }
        do {
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601
            let root = try decoder.decode(Root.self, from: data)
            let articles = root.articles
            for article in articles {
                print("article:", article, terminator: "n")
            }
        } catch {
            print(error)
        }

    }.resume()
}
fetchNews("us")
 

Это выведет:

статья: Статья (источник: __lldb_expr_111.Источник (идентификатор: необязательно («cnn»), имя: «CNN»), автор: Необязательно («Оливер Дарси, CNN Business»), заголовок: «Обратная реакция Такера Карлсона рассказывает нам кое-что важное о некоторых сторонниках Трампа -CNN», Описание статьи: ноль, url: https://www.cnn.com/2020/11/21/media/tucker-carlson-fox-news-traitor/index.html , urlToImage: https://cdn.cnn.com/cnnnext/dam/assets/201105014450-tucker-carlson-fox-news-presidential-election-fraud-super-tease.jpg , опубликованный в: 2020-11-21 16:11:00 0000, содержание: ноль)
статья: Статья (источник: __lldb_expr_111.Источник (идентификатор: Необязательно («usa-today»), название: «USA Today»), автор: необязательно («Джоэл Шеннон, Грейс Хаук»), заголовок: «Обновления по коронавирусу: Дональд Трамп-младший дал положительный результат; модель оценивает 471 тыс. смертей в США к марту; Куомо получит международную премию «Эмми» — USA TODAY», Описание статьи: Необязательно («Дональд Трамп-младший дал положительный результат накоронавирус. Модель предсказывает больше смертей. День благодарения во время пандемии случался и раньше. Последние новости о COVID. «), url: https://www.usatoday.com/story/news/health/2020/11/21/covid-news-donald-trump-jr-positive-thanksgiving-travel-not-advised/6367181002/ , urlToImage: https://www .gannett-cdn.com/presto/2020/11/21/NSTT/caa3ba8a-8e3c-4b49-82e2-2810caf33d05-Testing3.jpg?crop=1574,886,x0,y80amp;width=1600amp;height=800amp;fit=bounds , опубликованный в: 2020-11-21 15:56:15 0000, содержание: Необязательно («Вакцина против коронавируса может стать широко доступной только через несколько месяцев после 2021 года.rnUSA СЕГОДНЯ rN The U.S сообщил о рекордном количестве более 195 000 новых ежедневных случаев COVID-19 в пятницу, на той же неделе, когда … [ 11662 символа]»))
статья: Статья (источник: __lldb_expr_111.Источник (id: nil, название: «CBS Sports»), автор: Необязательно («»), заголовок: «Клемсон против Игра штата Флорида отложена за несколько часов до начала, поскольку команды разошлись во мнениях о том, играть или нет — CBS Sports», Описание статьи: необязательно («Поздний положительный тест игрока Clemson на COVID-19 является причиной резкой отсрочки»), url: https://www.cbssports.com/college-football/news/clemson-vs-florida-state-game-postponed-hours-before-kickoff-as-teams-disagreed-about-whether-to-play/ , urlToImage: https://sportshub.cbsistatic.com/i/r/2019/01/31/3cfd9702-8ef4-4f0d-9cc6-2601f4b3ad9c/thumbnail/1200×675/d00f9bb392291c844de43984526b773e/clemson.jpg , Опубликовано: 2020-11-21 15:28:00 0000, содержимое: необязательно («Нет. 4 Клемсон и штат Флорида должны были стартовать в полдень по восточному времени в Таллахасси, штат Флорида, игра, которая ознаменовала бы возвращение квотербека «Тигров» Тревора Лоуренса в строй после положительного COVID … [ 3139 символов] «)) ……

Комментарии:

1. Не могли бы вы также объяснить, почему вы используете ключи enum coding в модели? Для чего именно он используется?

2. Просто чтобы избежать создания описания свойства в вашей структуре. Возможно, в будущем вы захотите привести свою структуру в соответствие с CustomStringConvertible

Ответ №2:

статьи — описание «Ожидаемое строковое значение, но вместо него найдено значение null».

Изменить

 let description: String
 

Для

 let description: String?
 

Комментарии:

1. По какой-то причине, если я сделаю это необязательным, то мой «автор» станет нулевым, а если я сделаю свой «автор» нулевым, то мой «urlToImage» станет нулевым. Мне нужны эти данные, что я могу сделать?

Ответ №3:

В нем говорится, что в первом значении нет значения, можете ли вы опубликовать ответ json, который вы получаете, поскольку это было бы полезно. Другая возможность может заключаться в том, что ответ json находится в другом порядке, чем тот, который вы декодируете.

Вы могли бы просто изменить описание на необязательное, поскольку это избавило бы от проблемы, но тогда у вас не было бы описания, поэтому оно не полностью решает проблему

 let description: String?
 

Комментарии:

1. Да, сделать мое описание необязательным не помогает, поскольку мне это нужно, также по какой-то причине, если я сделаю это необязательным, мой автор станет нулевым. Кроме того, как мне получить ответ json?