Joe Leong
Joe Leong

Reputation: 95

Fetching data from JSON and display on UITableView

I'm fetching JSON data online and converting them to NSArray, and to String and class Arrays to manage the data. However, for some reason, the code exits the GetData() method after the line let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in

I've also verified that there was no issues with fetching the data, but it just can't be displayed on the table.

I've attached my project file also for download.

Codes from ViewController.swift

import UIKit

class ViewController: UIViewController, UITableViewDataSource {
var nameList = [NameManager]()

    @IBOutlet weak var NameTable: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        GetData()
        // Do any additional setup after loading the view, typically from a nib.
        NameTable.dataSource = self
        NameTable.reloadData()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func GetData(){
        let session = NSURLSession.sharedSession()
        let request = NSMutableURLRequest(URL: NSURL(string: "http://www.json-generator.com/api/json/get/bPfifKWNaq?indent=2")!)
        request.HTTPMethod = "GET"

        let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in

            if let error = error {
                print(error)
            }
            if let data = data{
                do{
                    let resultJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
                    let resultArray = resultJSON as? NSArray
                    for jsonObjectString in resultArray!{
                        let code = jsonObjectString["code"] as! String
                        let name = jsonObjectString["name"] as! String
                        let description = jsonObjectString["description"] as! String
                        self.nameList.append(NameManager(code: code, name: name, description: description))
                    }
                    self.nameList.count

                }catch _{
                    print("Received not-well-formatted JSON")
                }

            }
            if let response = response {
                let httpResponse = response as! NSHTTPURLResponse
                print("response code = \(httpResponse.statusCode)")
            }

        })
        task.resume()

    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        let count = nameList.count
        return count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
        let myCell = NameTable.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as UITableViewCell

        myCell.textLabel?.text = nameList[indexPath.row].name
        myCell.detailTextLabel?.text = nameList[indexPath.row].description

        return myCell
    }

}

Codes from NameManager.swift

import Foundation
class NameManager{

    var code:String
    var name:String
    var description:String

    init(code: String, name: String, description: String){
        self.code = code
        self.name = name
        self.description = description
    }
}

Upvotes: 0

Views: 116

Answers (1)

PK20
PK20

Reputation: 1066

session.dataTaskWithRequest is asynchronous and is automatically executed in background thread.

The dataTaskWithRequest is started when it sees the task.resume() and starts executing in background.

So, your program does not wait for its completion and starts to execute the instructions following it. In your example, your code will start to execute

    NameTable.dataSource = self
    NameTable.reloadData()

which are following GetData() method. Once the background execution is completed, the code you have in the completion handler is executed. So your tableView is not refreshed.

There are different ways you can approach this issue. one way is to include NameTable.reloadData() in your completion handler. Another way is to segue from a ViewController when background execution is completed.

Hope it helps.

EDIT:

import UIKit

class ViewController: UIViewController, UITableViewDataSource {
var nameList = [NameManager]()

    @IBOutlet weak var NameTable: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        NameTable.dataSource = self
        GetData()
        // Do any additional setup after loading the view, typically from a nib.

        //NameTable.reloadData()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func GetData(){
        let session = NSURLSession.sharedSession()
        let request = NSMutableURLRequest(URL: NSURL(string: "http://www.json-generator.com/api/json/get/bPfifKWNaq?indent=2")!)
        request.HTTPMethod = "GET"

        let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in

            if let error = error {
                print(error)
            }
            if let data = data{
                do{
                    let resultJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
                    let resultArray = resultJSON as? NSArray
                    for jsonObjectString in resultArray!{
                        let code = jsonObjectString["code"] as! String
                        let name = jsonObjectString["name"] as! String
                        let description = jsonObjectString["description"] as! String
                        self.nameList.append(NameManager(code: code, name: name, description: description))
                    }
                    self.nameList.count
                    dispatch_async(dispatch_get_main_queue(), {
                        self.NameTable.reloadData()
                    })
                }catch _{
                    print("Received not-well-formatted JSON")
                }

            }
            if let response = response {
                let httpResponse = response as! NSHTTPURLResponse
                print("response code = \(httpResponse.statusCode)")
            }

        })
        task.resume()

    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        let count = nameList.count
        return count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
        let myCell = NameTable.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as UITableViewCell

        myCell.textLabel?.text = nameList[indexPath.row].name
        myCell.detailTextLabel?.text = nameList[indexPath.row].description

        return myCell
    }

}

Upvotes: 3

Related Questions