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
}
}
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.