1

I am attempting to parse data from a website and then display it into a tableview on the press of a button. I am using swift 3, Xcode 8.2 beta and can not get the data to store into an array or display into the tableView. Here is my tableViewCell class:

class TableViewCell: UITableViewCell {
@IBOutlet weak var userIdLabel: UILabel!
@IBOutlet weak var titleLabel: UILabel!
override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}

Here is my viewController code:

import UIKit
class SecondViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
let urlString = "https://jsonplaceholder.typicode.com/albums"
@IBOutlet weak var tableView: UITableView!
  var titleArray = [String]()
  var userIdArray = [String]()
@IBAction func getDataButton(_ sender: Any) {
    self.downloadJSONTask()
     self.tableView.reloadData()
}
override func viewDidLoad() {
    super.viewDidLoad()
     tableView.dataSource = self
     tableView.delegate = self
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func downloadJSONTask() {
    let url = NSURL(string: urlString)
    var downloadTask = URLRequest(url: (url as? URL)!, cachePolicy:  URLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 20)
    downloadTask.httpMethod = "GET"


    URLSession.shared.dataTask(with: (url! as URL),  completionHandler: {(Data, URLResponse, Error) -> Void in
        let jsonData = try? JSONSerialization.jsonObject(with: Data!,  options: .allowFragments)
           print(jsonData as Any)
        if let albumArray = (jsonData! as AnyObject).value(forKey: "") as? NSArray {
            for title in albumArray{
                if let titleDict = title as? NSDictionary {
                    if let title = titleDict.value(forKey: "title") {
                        self.titleArray.append(title as! String)
                        print("title")
                        print(title)
                    }
                    if let title = titleDict.value(forKey: "userId")    {
                        self.userIdArray.append(title as! String)
                    }
                    OperationQueue.main.addOperation ({
                        self.tableView.reloadData()
                    })
                }
            }                
        }        
    }).resume()       
    }
 func tableView(_ tableView: UITableView, numberOfRowsInSection  section: Int) -> Int{
    return titleArray.count
  }
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
    cell.titleLabel.text = titleArray[indexPath.row]
    cell.userIdLabel.text = userIdArray[indexPath.row]
    return cell
    }
    }
Duck.P
  • 45
  • 1
  • 11
JeffBee
  • 13
  • 3

1 Answers1

0

There are many, many issues in your code, the worst is to use NSArray/NSDictionary in Swift.

The JSON is an array of dictionaries, the value for key title is String the value for userID is Int, so you have to declare your arrays

var titleArray = [String]()
var userIdArray = [Int]()

Never cast JSON data to most unspecified Any that's another no-go. Cast it always to the actual type. Another big problem is the Data parameter in the closure which clashes with the native struct in Swift3. Use always lowercase parameter labels. The request is not used at all in your code. And in Swift 3 use always the native structs URL, Data, URLRequest etc. Finally .allowFragments is nonsense since the JSON starts clearly with a collection type.

let url = URL(string: urlString)!
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: 20)
URLSession.shared.dataTask(with: request) { (data, response, error) in
    if error != nil {
        print(error!)
        return
    }

    do {
        if let jsonData = try JSONSerialization.jsonObject(with:data!, options: []) as? [[String:Any]] {
            print(jsonData)
            for item in jsonData {

                if let title = item["title"] as? String {
                    titleArray.append(title)
                }
                if let userID = item["userId"] as? Int {
                    userIdArray.append(userID)
                }
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            }
        }
    } catch let error as NSError {
        print(error)
    }
}.resume()

PS: Using two separate arrays as data source is horrible, too. Imagine that one of the optional bindings might fail and the number of items in the arrays will be different. That's a pretty invitation for a runtime crash.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thank you for the help. I have been lost (as you can see) trying to sort out how to properly load the data into the cell. THANK YOU SO MUCH for your help. When I am loading the data into the cells I am getting an error on this line: "cell.userIdLabel.text = userIdArray[indexpath.row]" of "cannot assign value of Int to type String". Is there a way to load an Int into a cell text label? – JeffBee Jan 26 '17 at 23:06
  • If you don't need the `Int` type anymore, declare `userIdArray` as `[String]` and populate the array `userIdArray.append("\(userID)")` – vadian Jan 27 '17 at 05:07
  • Thank you again! This project is learning experience and your help has be invaluable. I am new to application development and I will follow your recommendations. – JeffBee Jan 28 '17 at 06:37