简体   繁体   中英

Trying to return a value from API with JSON

Im trying to get data from newsapi.org/.

parseJSON returns error, and for some reason it can't get the data from NewsData.

I think there is some problem with my NewsData properties, which parseJSON func can't figure out the data.

here is the JSON (from urlString):

{
"status": "ok",
"totalResults": 38,
"articles": [

  {
    "source": {
      "id": "fox-news",
      "name": "Fox News"
    },
    "author": "Ryan Gaydos",
    "title": "Errol Spence Jr. retains welterweight titles in victory over Danny Garcia - Fox News",
    "description": "Errol Spence Jr. defeated Danny Garcia via unanimous decision Saturday night to retain the WBC and IBF welterweight titles.",
    "url": "https://www.foxnews.com/sports/errol-spence-jr-danny-garcia-boxing-2020",
    "urlToImage": "https://static.foxnews.com/foxnews.com/content/uploads/2020/12/Errol-Spence2.jpg",
    "publishedAt": "2020-12-06T05:39:59Z",
    "content": "Errol Spence Jr. defeated Danny Garcia via unanimous decision Saturday night to retain the WBC and IBF welterweight titles.\r\nThe judges scored the fight 116-112, 116-112, 117-111 in 

favor of Spence.\r… [+1417 chars]"
      }
    ]
}

and here is my code:

NewsData.Swift:

struct NewsData: Codable {
    let articles: [Article]
}

struct Article: Codable {
    let title: String
    let description: String
    let content: String
}

NewsManager.Swift:

func getNews() {
    let urlString = "\(baseURL)&apiKey=\(apiKey)"
    
    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(error)        
            } else {
                if let safeData = data {
                    if let news = self.parseJSON(safeData) {
                        print(news)
                    }
                }
            }
        }
        task.resume()
    }   
}

func parseJSON(_ data: Data) -> String? {
    let encoder = JSONDecoder()
    do {
        let encodedData = try encoder.decode(NewsData.self, from: data)

        let des = encodedData.articles[0].content
        let title = encodedData.articles[0].title
        let content = encodedData.articles[0].content
        
        return content
    } catch {
        print(error)
        return nil
    }
}

}

the return error is:

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

A DecodingError is one of the most precise and understandable errors ever.

Please read it entirely.

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

There are three significant information:

  1. What : valueNotFound indicates that somewhere a value is missing

  2. Where : The CodingPath is similar to a key path, concatenating the stringValue s results in:

     articles[1].content

    which points to the property content in the second item of articles

  3. Why : The debugDescription describes the actual error:

    • Expected indicates the wrong type → a non-optional String
    • found indicates the right type → <null> is not a value and requires an optional type

Solution: Declare content as optional

struct Article: Codable {
    let title: String
    let description: String
    let content: String?
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM