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
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()
}
}
}