iosswiftuisearchcontrolleruisearchresultscontroller

Autocomplete Search List issue In Swift


hello I have a very strange problem in my search functionality. I have successfully implemented the search functionality. I am getting a data from backend service. The problem is at some stage the data doesn't load up accurately in the suggestion area(tableView) according to the keywords typed. I also printing the result on console as well to check wether I am getting the accurate results against the keyword and the console shows accurate results, just the suggestion area doesn't load up exact result sometime. for example In my app If I want to search the city "Lahore". I typed full letters "Lahore"

It shows this enter image description here

but when I press x icon or backspace to remove the "e" it shows accurate results

enter image description here

I am just showing it for as an example. This is happening to almost all the time. Could you please take a look at my code and see whats wrong I am doing.

class CountryTableViewController: UITableViewController, UISearchResultsUpdating {

    var dict = NSDictionary()
    var filteredKeys = [String]()

    var resultSearchController = UISearchController()

    var newTableData = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.resultSearchController = ({

            let controller  = UISearchController(searchResultsController: nil)
            controller.searchResultsUpdater = self
            controller.dimsBackgroundDuringPresentation = false
            controller.searchBar.sizeToFit()
            self.tableView.tableHeaderView = controller.searchBar
            return controller


        })()

        self.tableView.reloadData()
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        if (self.resultSearchController.active) {

            return self.filteredKeys.count
        } else {

            return dict.count
        }

    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CountryTableViewCell

        if(self.resultSearchController.active){





                let cityName = (((self.dict["\(indexPath.row)"] as?NSDictionary)!["Country"] as?NSDictionary)!["city_name"] as?NSString)

               let stateName  = (((self.dict["\(indexPath.row)"] as?NSDictionary)!["Country"] as? NSDictionary)!["state_name"] as? NSString)

                 let shortName  = (((self.dict["\(indexPath.row)"] as?NSDictionary)!["Country"] as? NSDictionary)!["short_country_name"] as? NSString)


            if (cityName != "-" || shortName != "-"){
                cell.stateNameLabel.text = stateName as? String
                cell.cityNameLabel.text = cityName as? String
                 cell.shortNameLabel.text = shortName as? String

            }

                      return cell

        }else{
            if let cityName = (((self.dict["\(indexPath.row)"] as?NSDictionary)!["Country"] as?NSDictionary)!["city_name"] as?NSString){
            cell.cityNameLabel.text = cityName as String
            }
            return cell
        }



    }



    func updateSearchResultsForSearchController(searchController: UISearchController) {

        let searchWord = searchController.searchBar.text!

        getCountriesNamesFromServer(searchWord)

        self.filteredKeys.removeAll()

        for (key, value) in self.dict {

            let valueContainsCity: Bool = (((value as? NSDictionary)?["Country"] as? NSDictionary)?["city_name"] as? String)?.uppercaseString.containsString(searchWord.uppercaseString) ?? false

            let valueContainsCountry: Bool = (((value as? NSDictionary)?["Country"] as? NSDictionary)?["country_name"] as? String)?.uppercaseString.containsString(searchWord.uppercaseString) ?? false

            if valueContainsCity || valueContainsCountry{ self.filteredKeys.append(key as! String) }




        }

        self.tableView.reloadData()
    }




    func getCountriesNamesFromServer(searchWord:String){


        let url:String = "http://localhost"
        let params = ["keyword":searchWord]



        ServerRequest.postToServer(url, params: params) { result, error in

            if let result = result {
                print(result)



                self.dict = result

            }
        }

    }

}

Solution

  • You are reloading your table after your request starts instead of when it finishes, so your dict still has the results from the last query it ran.

    Move everything in your updateSearchResults.. method that is after you call getCountriesNamesFromServer into the completion handler for your network request after you do self.dict = result

    Your new methods would be:

    func updateSearchResultsForSearchController(searchController: UISearchController) {    
        let searchWord = searchController.searchBar.text!    
        getCountriesNamesFromServer(searchWord)        
    }
    
    func getCountriesNamesFromServer(searchWord:String) {        
        let url:String = "http://localhost"
        let params = ["keyword":searchWord]
    
        ServerRequest.postToServer(url, params: params) { result, error in    
            if let result = result {
                print(result)
    
                self.dict = result
    
                self.filteredKeys.removeAll()
    
                for (key, value) in self.dict {
                    let valueContainsCity: Bool = (((value as? NSDictionary)?["Country"] as? NSDictionary)?["city_name"] as? String)?.uppercaseString.containsString(searchWord.uppercaseString) ?? false
    
                    let valueContainsCountry: Bool = (((value as? NSDictionary)?["Country"] as? NSDictionary)?["country_name"] as? String)?.uppercaseString.containsString(searchWord.uppercaseString) ?? false
    
                    if valueContainsCity || valueContainsCountry {
                        self.filteredKeys.append(key as! String)
                    }
                }
    
                self.tableView.reloadData()   
            }               
        }
    }