Search code examples
swiftxcode6uisearchbarsearchfiltercollection

search bar category filters with swift


I am trying to implement a search bar that categorizes search queries based on people and places, so the user switches back and forth between the two categories of search. I have the search bar working for people but am having trouble figuring out how to go back and forth between the 2 search categories...How would I implement this? Below is the code...

Thank you in advance!

//
//  SearchViewController.swift
//  TravelAppSwiftPrototype
//

import UIKit

class SearchViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate {

    var persons = [People]()
    var place = [Places]()

    var filteredPersons = [People]()
     var filteredPlaces = [Places]()

    override func viewDidLoad() {
        // Sample Data for PeopleArray
        self.persons = [People(category:"People", name:"Anthony Valentine"),
            People(category:"People", name:"Ben Matthews"),
            People(category:"People", name:"Mark Druffel"),
            People(category:"People", name:"Brittany Donnelly"),
            People(category:"People", name:"Thomas Meier"),
            People(category:"People", name:"Alex Curtis"),
            People(category:"People", name:"David Moss"),
            People(category:"People", name:"Sara Flege"),
            People(category:"People", name:"Mark Cuban"),
            People(category:"People", name:"Elon Musk"),
            People(category:"People", name:"Steve Jobs"),
            People(category:"People", name:"Steve Meier"),
            People(category:"People", name:"Dan Meier"),
            People(category:"People", name:"Christine Meier"),
            People(category:"People", name:"Bill Gates"),
            People(category:"People", name:"Matt Harris")]


        // Sample Data for PlacesArray
        self.place = [Places(category:"People", place:"Rome, Italy"),
            Places(category:"Places", place:"Paris, France"),
            Places(category:"Places", place:"Barcelona, Spain"),
            Places(category:"Places", place:"Girona, Spain"),
            Places(category:"Places", place:"Lloret de Mar, Spain"),
            Places(category:"Places", place:"London, United Kingdom"),
            Places(category:"Places", place:"Perth, Australia"),
            Places(category:"Places", place:"Berlin, Germany"),
            Places(category:"Places", place:"Lyon, France"),
            Places(category:"Places", place:"Munich, Germany"),
            Places(category:"Places", place:"Bruges, Belgium"),
            Places(category:"Places", place:"Buenes Aires, Argentina"),
            Places(category:"Places", place:"Milan, Italy")]



        // Reload the table
        self.tableView.reloadData()
    }

     //how to implement search filtering for places...?????
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == self.searchDisplayController!.searchResultsTableView {
            return self.filteredPersons.count
        } else {
            return self.persons.count
        }
    }



    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        //ask for a reusable cell from the tableview, the tableview will create a new one if it doesn't have any
        let cell = self.tableView.dequeueReusableCellWithIdentifier("SearchFriendsCell") as UITableViewCell

        var people : People
        // Check to see whether the normal table or search results table is being displayed and set the Candy object from the appropriate array
        if tableView == self.searchDisplayController!.searchResultsTableView {
            people = filteredPersons[indexPath.row]
        } else {
            people = persons[indexPath.row]
        }

        // Configure the cell
        cell.textLabel.text = people.name
        cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator

        return cell
    }

    func filterContentForSearchText(searchText: String, scope: String = "All") {
        self.filteredPersons = self.persons.filter({( people : People) -> Bool in
            var categoryMatch = (scope == "All") || (people.category == scope)
            var stringMatch = people.name.rangeOfString(searchText)
            return categoryMatch && (stringMatch != nil)
        })
    }

    func searchDisplayController(controller: UISearchDisplayController!, shouldReloadTableForSearchString searchString: String!) -> Bool {
        let scopes = self.searchDisplayController!.searchBar.scopeButtonTitles as [String]
        let selectedScope = scopes[self.searchDisplayController!.searchBar.selectedScopeButtonIndex] as String
        self.filterContentForSearchText(searchString, scope: selectedScope)
        return true
    }

    func searchDisplayController(controller: UISearchDisplayController!,
        shouldReloadTableForSearchScope searchOption: Int) -> Bool {
            let scope = self.searchDisplayController!.searchBar.scopeButtonTitles as [String]
            self.filterContentForSearchText(self.searchDisplayController!.searchBar.text, scope: scope[searchOption])
            return true
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.performSegueWithIdentifier("FriendsDetail", sender: tableView)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
        if segue.identifier == "FriendsDetail" {
            let candyDetailViewController = segue.destinationViewController as UIViewController
            if sender as UITableView == self.searchDisplayController!.searchResultsTableView {
                let indexPath = self.searchDisplayController!.searchResultsTableView.indexPathForSelectedRow()!
                let destinationTitle = self.filteredPersons[indexPath.row].name
                candyDetailViewController.title = destinationTitle
            } else {
                let indexPath = self.tableView.indexPathForSelectedRow()!
                let destinationTitle = self.persons[indexPath.row].name
                candyDetailViewController.title = destinationTitle
            }
        }
    }



    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}



//  Friends.swift
//  TravelAppSwiftPrototype
//
import Foundation

struct People {
    let category : String
    let name : String
}



//  Places.swift
//  TravelAppSwiftPrototype
//
import Foundation

struct Places {
    let category : String
    let place : String
}

Solution

  • The key is this method:

    func filterContentForSearchText(searchText: String, scope: String = "All") {
        self.filteredPersons = self.persons.filter({( people : People) -> Bool in
            var categoryMatch = (scope == "All") || (people.category == scope)
            var stringMatch = people.name.rangeOfString(searchText)
            return categoryMatch && (stringMatch != nil)
        })
    }
    

    You need to write that method in such a way that it takes account of the scope button settings. Then you set yourself up as the search bar's delegate so that you hear about the scope button being changed. When it changes, do your filtering and reload the results table.