-1

Problem. I want to parse the json from here and show on a table view, i am using swift 4 and Decodable. but i am getting a type mismatch error. Link to json:

https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=50fb91212a47432d802b3b1ac0f717a3

My Struct looks like this.

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

struct Article : Decodable {
    let source: Source
    let author, title, description: String
    let url: URL
//  let publishedAt: Date
    let urlToImage: String
}

struct Source: Decodable {
    let id, name: String
}

My ViewDidLoad Looks like this :

  var articles : [Article]? = []

    override func viewDidLoad() {
        super.viewDidLoad()
        tableview.delegate = self
        tableview.dataSource = self
        fetchArticles()
    }

    func fetchArticles(){
    let jsonURLString = "https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=50fb91212a47432d802b3b1ac0f717a3"
    guard let url = URL(string: jsonURLString) else { return }
      URLSession.shared.dataTask(with: url) { (data,response,err) in
           guard let data = data else { return }
            self.myArticles = [Article]()
            do{
                let decoder = JSONDecoder()
                decoder.dataDecodingStrategy = .base64
                let root = try decoder.decode(Root.self, from: data)
                self.myArticles = root.articles
                DispatchQueue.main.async {
                    self.tableview.reloadData()
                }
            } catch let error{
                print(error)
            }
        }.resume()
}

My cellForRowAtIndexPath

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let myCell = tableView.dequeueReusableCell(withIdentifier: "articleCell", for: indexPath) as! ArticleCell

    let article = self.myArticles[indexPath.row]
    myCell.title.text = article.title
    myCell.body.text = article.description
    myCell.author.text = article.author
    myCell.imgView.downloadImage(from: ("https://tctechcrunch2011.files.wordpress.com/2017/04/uber-vs-waymo.png"))

    return myCell
}

Error i am getting.

No errors, nothing loads to the table view.
santoshaa
  • 173
  • 2
  • 4
  • 10

1 Answers1

0

The error is clear. You are going to decode an array but the object is a dictionary.

This decodes the JSON including the special decoding to URL and Date.

The root object is a dictionary, the key articles contains the articles and source is a dictionary, not an array

struct Root : Decodable {
    let status : String
    let articles : [Article]
}

struct Article : Decodable {
    let source: Source
    let author, title, description: String
    let url: URL
    let publishedAt: Date
    let urlToImage: String
}

struct Source: Decodable {
    let id, name: String
}

var articles = [Article]()

do {
   let decoder = JSONDecoder()
   decoder.dateDecodingStrategy = .iso8601
   let root = try JSONDecoder().decode(Root.self, from: data)
   self.articles = root.articles
   DispatchQueue.main.async {
      self.tableview.reloadData()
   }
} catch { print(error) }

There is no need to use classes inheriting from NSObject

And do not declare the data source object as optional and get the same item a couple of times in cellForRow and it's indexPath.row

 ...
 let article = self.articles[indexPath.row]
 myCell.title.text = article.title
 myCell.body.text = article.description
 myCell.author.text = article.author
 ...
vadian
  • 274,689
  • 30
  • 353
  • 361
  • OK, i changed as per your comment, still ! – santoshaa Dec 17 '17 at 18:09
  • I have posted the new code in the question above. Can you please check once. Now there is no error and i understood the problem. But why table view is not loading! – santoshaa Dec 17 '17 at 18:15
  • Please don't edit the question updating the code with suggestions in answers. It could confuse other readers. And – btw – you didn't consider my suggestion to declare the data source array as non-optional. I made a mistake. `root.articles` must be assigned to `self.articles`. I updated the answer. – vadian Dec 17 '17 at 18:27
  • Hurray! thanks a lot, i understood the problem now, for people who are going to look at the question, please see that i have updated the question with working code. Sorry for the mix up. I tried to post the 107 lines of code in my class in answer but it did not let me! – santoshaa Dec 17 '17 at 18:32
  • Don't do that. The question became pointless because after editing the code you won't get a type mismatch anymore as stated in the question and others can't reproduce the issue and its solution. – vadian Dec 17 '17 at 18:39
  • Going by the same rules, Why the following does not work? – santoshaa Dec 20 '17 at 05:40
  • The link returns a 404 error. But please read the JSON. It's very easy and straightforward because there are only two collection types and four value types. – vadian Dec 20 '17 at 05:45
  • please remove quote " in the end from the link while opening in browser, it works. – santoshaa Dec 20 '17 at 06:42