iosswiftuitableviewuisearchbar

Display city names in a TableView


I'd like to display all city names on a tableview based on what the user types in a searchBar. For example if the user types "New York" inside the searchBar I want to be displayed all the results the API gives me. I'm using an API which returns JSON data.

Right now I'm using this delegate methods:

extension searchViewController : UISearchBarDelegate{

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

        RequestAPI.queryCities(cityNameString: searchBar.text!) { (cities) in
        for iterator  in 0...cities.geonames.count-1 {
            self.citiesQueried.append(cities.geonames[iterator])
        }
    }

        self.tableView.reloadData()
}


func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    print("cancel button clicked")
    self.citiesQueried.removeAll()
    self.tableView.reloadData()
}
}

citiesQueried is an array that I declared empty before in the viewController an has the task of collecting all the data resulted from the API request.

These are the delegate methods of UITableView:

extension searchViewController : UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return citiesQueried.count
}


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

The problem is that sometime it works and sometime it doesn't and I need to press 2 times the search button in order to see the cities displayed on the tableView. I think something is missing, I hope some of you could give me a suggestion on how to solve this issue


Solution

  • You have to reload the table view inside the completion handler of the asynchronous task

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    
        RequestAPI.queryCities(cityNameString: searchBar.text!) { (cities) in
            for iterator  in 0..<cities.geonames.count {
                self.citiesQueried.append(cities.geonames[iterator])
            }
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    }
    

    Side note:

    The name cities implies to be an array but it seems to be a single object. Then the for loop is not needed and name the parameter in singular form

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    
        RequestAPI.queryCities(cityNameString: searchBar.text!) { city in          
            self.citiesQueried = city.geonames         
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    }