48

I am a newbie to Swift and I am trying to add search functionality to my UITableView which is in a UIViewController class. I googled a lot and found that UISearchDisplayController has been deprecated and replaced by UISearchController. When I tried to search for tutorials I did not find any specifically for UITableView. Some of them were for implementing in UITableViewController. So here are my questions:

  1. Can we implement UISearchController in a UITableView that is in a UIViewController class? (I guess we can)

  2. If we can, please convert these line of codes written in Objective-C. Or if there are some really good tutorials please let me know.

    @property (strong, nonatomic) UISearchController *searchController;
    
    UITableViewController *searchResultsController = [[UITableViewController alloc] init];
    
    // Init UISearchController with the search results controller
     self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
    
    // Link the search controller
    self.searchController.searchResultsUpdater = self;
    

Source

EDIT : I am trying to assign the search results updater in as

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating {

    override func viewDidLoad() {

       super.viewDidLoad()
       self.view.backgroundColor = UIColor.blackColor() 
       self.addTableViewWithSection() 
       self.searchResultsController = UITableViewController()           
       var controller = UISearchController(searchResultsController: nil)            
       controller.searchResultsUpdater = self           
       controller.dimsBackgroundDuringPresentation = false   
    }
}

*However on the line controller.searchResultsUpdater = self i get the eroor as Cannot assign a value of typ "ViewController" to a value of type "UISearchResultsUpdating?" .. So i really doubt if i can use UISearchController in UIViewController type class.

shim
  • 9,289
  • 12
  • 69
  • 108

3 Answers3

74

Yes, the way search works has been radically changed for what I consider to be a better system. The new system is much better and straight to the point for most simple implementations. Using it is pretty straightforward.

First, make your class comply with the UISearchResultsUpdating protocol.

class MyTableViewController: UITableViewController, UISearchResultsUpdating {}

Add it the search controller property:

class MyTableViewController: UTableViewController, UISearchResultsUpdating {
    let searchController = UISearchController(searchResultsController: nil)
}

Add the search bar in viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()

    searchController.searchResultsUpdater = self
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.dimsBackgroundDuringPresentation = false
    searchController.searchBar.sizeToFit()
    self.tableView.tableHeaderView = searchController.searchBar
}

And finally, implement the updateSearchResults:for method that comes from the UISearchResultsUpdating protocol:

func updateSearchResults(for searchController: UISearchController) {

}

Your implementation of this method will of course depend on where you are searching the data from. It will update your current table view with the contents of your search as you type them. Make sure you update your data source and reload the table view in the updateSearchResultsForSearchController method. Again, it updates as you type so make sure that if your data to search in is big or if you are searching from the internet, add some concurrency in this method.

If you want to use a different controller to populate your search results with, you can pass that VC when initialising the searchController property.

EDIT: I have reread your question and it looks like I forgot to add something important.

UITableViewController has a member called tableView. You can grab the controller's table view , but to populate your UITableView, you don't need to touch it. You can't use the SearchController logic directly with UITableView. You gotta work with the controller to get it there. Use the UITableViewController delegate and data source methods to get your table UI updated with your search results.

Please read on using UITableViewController, UITableViewDelegate, and UITableViewDataSource so you can understand how to get your search results there.

Andy Ibanez
  • 12,104
  • 9
  • 65
  • 100
  • what if this line was class MyTableViewController: UITableViewController, UISearchResultsUpdating {} as class MYTableView: UIViewController and had tableview created or have an outlet there ...does this work? –  Apr 16 '15 at 03:10
  • The name of class doesn't matter but it makes no sense to leave the Controller part out as you are effectively defining a controller, not a view. Also you don't need to manually create a UITableView because UITableViewController has one ready to be used by you. Whether you created this controller in IB or fully by code, your controller can reference it via `self.tableView`. But again, you don't need to do that to populate your table view. – Andy Ibanez Apr 16 '15 at 03:16
  • The scope of this answer doesn't deal with using the table view controller, the delegate, or the data source. But feel free to read a [tutorial](http://blog.teamtreehouse.com/introduction-to-the-ios-uitableviewcontroller) on the topic. – Andy Ibanez Apr 16 '15 at 03:19
  • 1
    i had already a ViewController with many sub views and a large TableView and i have to implement search functionality to that table view..so ,i am seeking around ...anyway thanks man!!! i will try to implement this –  Apr 16 '15 at 03:28
  • can you please see the updated question..i am really stuck now –  Apr 16 '15 at 05:09
  • I LOL'd when I got to: "add some concurrency" :) – Andres Jaan Tack Apr 18 '16 at 08:22
  • 1
    If you want to add to any UIView then you can use `myView. addSubview(searchController.searchBar)` – Ariq Jan 18 '19 at 10:08
27

In case of anyone, who is freaking around like me..this code might help

class ViewController: UIViewController , UITableViewDataSource, UITableViewDelegate,UISearchResultsUpdating {

    @IBOutlet weak var tblView: UITableView!

    var tabledata = ["lucques","chickendijon","godaddy","amazon","chris","ambata","bankofamerica","abelcine","AUTO + TRANSPORTATION","BILLS + UTILITIES","FOOD + DINING","HEALTH","AutoCare", "Auto Payment" , "Gas+Fuel","Electric Bill", "Internet/Television","Fast Foodd", "Gorceries" , "Restaurants","Gym Membership", "Health Insurance","auto","note-bullet","knife","heart"]

    var filteredTableData = [String]()
    var resultSearchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()
        tblView.delegate = self
        tblView.dataSource = self
        self.resultSearchController = ({
            let controller = UISearchController(searchResultsController: nil)
            controller.searchResultsUpdater = self
            controller.dimsBackgroundDuringPresentation = false
            controller.searchBar.sizeToFit()
            controller.searchBar.barStyle = UIBarStyle.Black
            controller.searchBar.barTintColor = UIColor.whiteColor()
            controller.searchBar.backgroundColor = UIColor.clearColor()
            self.tblView.tableHeaderView = controller.searchBar
            return controller
        })()
        self.tblView.reloadData()
    }

     func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if self.resultSearchController.active {
           return self.filteredTableData.count
        }else{
            return self.tabledata.count
       }
    }
     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var section = indexPath.section
        var row = indexPath.row
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier:"addCategoryCell")
        cell.selectionStyle =  UITableViewCellSelectionStyle.None
        cell.backgroundColor = UIColor.clearColor()
        cell.contentView.backgroundColor = UIColor.clearColor()
        cell.textLabel?.textAlignment = NSTextAlignment.Left
        cell.textLabel?.textColor = UIColor.blackColor()
        cell.textLabel?.font = UIFont.systemFontOfSize(14.0)

        if self.resultSearchController.active {
              cell.textLabel?.text = filteredTableData[indexPath.row]
        } else {
                 cell.textLabel?.text = tabledata[indexPath.row]
        }
        return cell
    }

    func updateSearchResultsForSearchController(searchController: UISearchController) {
        filteredTableData.removeAll(keepCapacity: false)
        let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text)
        let array = (tabledata as NSArray).filteredArrayUsingPredicate(searchPredicate)
        filteredTableData = array as! [String]
        self.tblView.reloadData()

    }
}
Lamour
  • 3,002
  • 2
  • 16
  • 28
  • 1
    FYI, you're assumption that you can scope initialize a variable is a very very bad assumption. Never, ever do what you're doing with self.resultSearchController in a method body. – TheCodingArt Jul 07 '15 at 14:23
  • should i make that lazy variable and intialize? –  Jul 08 '15 at 06:24
  • Yes, very much so if you would like the initialization all in one place – TheCodingArt Jul 08 '15 at 11:21
  • yeah..that might be good..this was the one when i was learning about SearchController –  Jul 09 '15 at 04:02
  • What if , that i want to get the indexpath of search results , and have a segue , how to read the indexpath for search results ? Thanks you – Mudith Chathuranga Silva Sep 25 '15 at 04:27
  • 1
    after you search..you can go with didselectrowatindexpath delegate method of tableview and segue from there –  Sep 25 '15 at 05:04
0

For those looking for a bit more context on all the aspects of implementing this, here's a tutorial on how to implement UISearchController

In addition to the above answer by Andy Ibanez, you also need to add code to your UITableViewDataSource methods to show the newly filtered results in the tableview.

Also, don't forget to call tableView.reloadData() in your updateSearchResults method - the UISearchController does not automatically tell the tableView to reload its data.

Community
  • 1
  • 1
Bdebeez
  • 3,542
  • 3
  • 31
  • 32