Technicolor
Technicolor

Reputation: 1619

iOS updateSearchResultsForSearchController only called once

I've been trying to implement a UISearchController in an app, and as reference, I was following this tutorial. The tutorial covered a bit more than I needed (like scope), so I only skimmed it, but when I ran my test app, the search didn't work. When I typed in the search bar, it only filtered results for the first character I typed in, regardless of whether I pressed "search" or not. For example, if I typed in "dolphin", it would only show results that contained "d". By printing inside updateSearchResultsForSearchController, I confirmed that it was only called once.

However, if I deleted everything in the search bar, the results would go back to being unfiltered, and if I typed in something again, it would (again) only filter for the first character.

I also tried the workaround suggested here, but the issue still persisted. This is my code:

class SearchController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
    let data = [
        "bottlenose dolphin": 111,
        "manta ray": 172,
        "humphead wrasse": 388,
        "Commerson's dolphin": 19
        // etc.
    ]

    var results = [String: Int]()
    let searchController = UISearchController(searchResultsController: nil)

    override func viewDidLoad() {
        super.viewDidLoad()
        searchController.searchResultsUpdater = self
        searchController.searchBar.delegate = self
        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true
        tableView.tableHeaderView = searchController.searchBar
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if searchController.active && searchController.searchBar.text != "" {
            return results.count
        } else {
            return data.count
        }
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        if searchController.active && searchController.searchBar.text != "" {
            let index = results.startIndex.advancedBy(indexPath.row)
            cell.textLabel!.text = results.keys[index]
        } else {
            let index = data.startIndex.advancedBy(indexPath.row)
            cell.textLabel!.text = data.keys[index]
        }
        return cell
    }

    func search(searchText: String) {
        let temp = data.filter({(element: (String, Int)) -> Bool in
            return element.0.lowercaseString.containsString(searchText.lowercaseString)
        })
        for element in temp { results[element.0] = element.1 }
        tableView.reloadData()
    }

    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
        updateSearchResultsForSearchController(searchController)
    }

    func updateSearchResultsForSearchController(searchController: UISearchController) {
        search(searchController.searchBar.text!)
    }
}

There's the chance that I missed a step when skimming the tutorial, but I've looked through it several more times to no avail. How can I make the search work properly?

Edit: I also just noticed that sometimes the search would pop up results that didn't even contain the first character of the query. For example, using a different set of data, searching "J" popped up "Silicon Valley"...

Upvotes: 0

Views: 466

Answers (1)

bluedome
bluedome

Reputation: 2459

You forget to remove previous results.

func search(searchText: String) {
    let temp = data.filter({(element: (String, Int)) -> Bool in
        return element.0.lowercaseString.containsString(searchText.lowercaseString)
    })
    results.removeAll() // clear previous ones
    for element in temp { results[element.0] = element.1 }
    tableView.reloadData()
}

Upvotes: 1

Related Questions