skip to Main Content

I made API Request and wanted to add it in Table View. Is realoadData() being called earlier than the loading of data?. There is an issue with tableView because the API call is working fine. Below is the code :

class ViewController: UIViewController {

var tableView : UITableView!
var listOfHolidays = [HolidayDetails](){
    didSet{
        DispatchQueue.main.async{
            self.tableView.reloadData()
            self.navigationItem.title = "(self.listOfHolidays.count) Holidays found"
        }
    }
}

calling Fetch Function in ViewDidLoad.

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    DataFetch { (holidaydetails) in
        for items in holidaydetails{
            self.listOfHolidays.append(items)
            print(items)
        }
    
    }
}

Fetch Function for API Call.

func DataFetch(completionHandler : @escaping ([HolidayDetails]) -> Void){
    guard let url = URL(string: "https://holidayapi.com/v1/holidays?   pretty&country=IN&year=2020&key=457d9815-2e0a-4140-9515-0f6ef0d5f8b9") else{return(print("Error"))}
    
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        
        guard let data = data else{ return print("Error")}
        do{
            let holidayData = try JSONDecoder().decode(Holidays.self, from: data)
            let holidayDetail = holidayData.holidays
            completionHandler(holidayDetail)
        }
        catch{
            let error = error
            print(error.localizedDescription)
        }
    }
    task.resume()
}
}

Extensions:

extension ViewController : UITableViewDataSource,UITableViewDelegate {

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

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

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath)
      let holidays = listOfHolidays[indexPath.row]
      cell.textLabel?.text = holidays.name
      cell.detailTextLabel?.text = holidays.date
      return cell
  }

}

I also have another file with Data Model :

import Foundation

struct Holidays : Codable {
   var holidays : [HolidayDetails]
}
struct HolidayDetails : Codable {
   var name : String
   var date : String
}

2

Answers


  1. Your tableView is nil: var tableView : UITableView!

    You just need to initialize it, for example like this: var tableView = UITableView()

    Also you just learned that it is not good practice to use !.

    Login or Signup to reply.
  2. As @Larme commented, the problem is very likely in your didSet oberserver.
    Somewhere, you set the listOfHolidays to a value before the view of that controller did load, e.g. before the tableView outlet is connected to the UITableView.
    Updating the UI from within a setter is not always a good idea. But if you really want it, you could circumvent the crash by checking if the tableView is nil:

    var listOfHolidays = [HolidayDetails](){
        didSet{
            guard self.tableView != nil else { return } 
            DispatchQueue.main.async{
                self.tableView.reloadData()
                self.navigationItem.title = "(self.listOfHolidays.count) Holidays found"
            }
        }
    }
    

    There should be no reload issue with this code: if tableView is nil, reloadData will not be called, but this does not matter, because as soon as the outlet is connected (before viewDidLoad), it reloading will be triggered by itself.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search