0

I am trying to get an API call to populate the cells of a list view but cannot seem to get the data to be gathered before the cells are generated. I have tried making a completion handler as like here to no avail as well as a semaphore from the same link. While the completion handler compiled, it still did not get the data in time when executing (admittedly it was my first attempt at a completion handler). Here is the original code w/o the completion handler:

override func viewDidLoad() {
    super.viewDidLoad()

    RestaurantListView.delegate = self
    RestaurantListView.dataSource = self
    //API setup
    guard let url = URL(string: "https://myURL.com") else {
        print("ERROR: Invalid URL")
        return
    }
    let task = URLSession.shared.dataTask(with: url) {

        (data, response, error) -> Void in

        // URL request is complete
        guard let data = data else {
            print("ERROR: Unable to access content")
            return
        }

        guard let blog = try? JSONDecoder().decode(Blog.self, from: data) else {
            print("Error: Couldn't decode data into Blog")
            return
        }
        self.myData = blog
    }
    task.resume()
}

The table and cells are initialized below these functions:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 100
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = RestaurantListView.dequeueReusableCell(withIdentifier: "cell")
    cell?.textLabel?.text = myAPIValue
    return cell!
    }

I have several print statements to track the program and it goes through viewDidLoad then the first tableView which sets up the table then the second which handles the cells, finally it goes through the URL task.

I have rewritten this dozens of different ways and have no idea how to make this execute in the correct order.

rmaddy
  • 314,917
  • 42
  • 532
  • 579

2 Answers2

2

You need to reload the table , as this line URLSession.shared.dataTask(with: url) triggers an asynchronous task that isn't in the same sequential order of your lines of code

guard let blog = try? JSONDecoder().decode(Blog.self, from: data) else {
     print("Error: Couldn't decode data into Blog")
     return
}
self.myData = blog

DispatchQueue.main.async{
    RestaurantListView.reloadData()
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
1

You have to save your data in a variable as you can see as follow, I used arrayOfData. Look the reloadData() function which is called after saving the data.

func downloadData (){
    let url = URL(string: "http://www.url.com")

    if let url = url {
        let task = URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
            do {
                if let dataResponse = data{
                    let responseDecoded = try JSONDecoder().decode(Response.self, from: dataResponse)
                    DispatchQueue.main.async {
                        self.arrayOfData = responseDecoded.results ?? []
                        self.RestaurantListView.reloadData()
                    }
                } 
            }
            catch {
                print("Error: \(error)")
            }
        })

        task.resume()
    }
}

You have to conform the protocol with that data

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    /**If you have no elements you should return 0**/
    return arrayOfData.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = RestaurantListView.dequeueReusableCell(withIdentifier: "cell"){
        cell.textLabel?.text = arrayOfData[indexPath.row].name
        return cell
    }
    return UITableViewCell()
}
Amjimenez
  • 21
  • 5