skip to Main Content

I’m having a hard time adding a functioning search bar to the top of my Table View. My code without it runs fine for selecting the colleges, but I need a search table to filter through the list of universities.

I’ve tried to add a search bar that I find from online sources, but they end up using arrays for their list of items. My code doesn’t do it in the same format for the items I show in my TableView. That would be great if there is a way to add a search bar without creating an array for the items listed in my Table view.

import UIKit

class MasterViewController: UITableViewController{
        
        
    var detailViewController: DetailViewController? = nil
    var objects = [Any]()
    
    
    
    var UniName: [String] = ["The University of Texas at Austin", "Rice University", "Texas A&M University", "Baylor university", "The University of Texas at El Paso", "southern methodist university", "The University of Texas at Dallas", "Texas Tech University", "University of North Texas", "Texas A&M University-Commerce"]
    var UniAddress: [String] = ["110 Inner Campus Drive Austin, TX 78705", "6100 Main St., Houston, TX 77005-1892", "Administration Building, 400 Bizzell St, College Station, TX 77843", "1311 S 5th St, Waco, TX 76706", "500 W University Ave, El Paso, TX 79968", "6425 Boaz Lane, Dallas, TX 75205", "800 W Campbell Rd, Richardson, TX 75080", "2500 Broadway, Lubbock, TX 79409", "1155 Union Cir, Denton, TX 76203", "2200 Campbell St, Commerce, TX 75428"]
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        navigationItem.leftBarButtonItem = editButtonItem
        if let split = splitViewController {
            let controllers = split.viewControllers
            detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
        }
    }
    
    
    
    
    override func viewWillAppear(_ animated: Bool) {
        clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed
        super.viewWillAppear(animated)
    }
    // MARK: - Segues
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetail" {
            if let indexPath = tableView.indexPathForSelectedRow {
                let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
                controller.setNewAddress(Member: UniName[indexPath.row], formap: UniAddress[indexPath.row])
                controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
                controller.navigationItem.leftItemsSupplementBackButton = true
            }
        }
    }
    
    // MARK: - Table View
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return UniName.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableViw.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel!.text = UniName[indexPath.row]
        return cell
    }
    
}

2

Answers


  1. Your question is quite broad so first things first. You should probably first start with a model definition for your data.

    // This is a model for our table
    struct University {
        let name: String
        let address: String
    
        static let allUniversities = [
            University(name: "The University of Texas at Austin", address: "110 Inner Campus Drive Austin, TX 78705"),
            University(name: "Rice University", address: "6100 Main St., Houston, TX 77005-1892"),
            University(name: "Texas A&M University", address: "Administration Building, 400 Bizzell St, College Station, TX 77843")
            // Add more universities here
        ]
    }
    

    This will clearly separate the model from the controller logic.

    The best way to customize tables is to not use UITablewViewController but rather use UITableView with UISearchBar inside UIViewController. If using a storyboard it would look like this:

    Storyboard hierarchy

    It’s important to add the search bar into the UITableView on top position. Now here’s what the view controller could look like.

    class ViewController: UIViewController {
    
        // Make sure you connect those IBOutlets to your Storyboard
        @IBOutlet var tableView: UITableView!
        @IBOutlet var searchBar: UISearchBar!
    
        // This is our main data source
        let data: [University] = University.allUniversities
    
        // This is where we save filtered results from search and display it
        var searchedResults: [University] = []
    
        // This is a flag that determines if to show all the results or only the searched results
        var isSearching = false {
            didSet {
                tableView.reloadData() // Reload the data if the flag changes
            }
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            tableView.dataSource = self
            searchBar.delegate = self
        }
    
        // MARK: - Helper methods
    
        /// Retuns active dataset based on the search state
        func activeDataset() -> [University] {
            if isSearching {
                return searchedResults
            } else {
                return data
            }
        }
    
        /// Returns a list of univerties matching given query
        func filteredUniversities(query: String) -> [University] {
            return data.filter { $0.name.contains(query) }
        }
    }
    

    As you can see in the viewDidLoad method, we added the ViewController as dataSource for the table and delegate for the search bar so we need to make sure to conform to those protocols

    
    extension ViewController: UITableViewDataSource {
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
            let universities = activeDataset()
            let university = universities[indexPath.row] // Get data for the row
    
            cell.textLabel!.text = university.name // Update the cell with the data
    
            return cell
        }
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1 // Our data are all in 1 section
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return activeDataset().count
        }
    }
    
    

    Here we created a logic to show either search results or all the data depending on if the search is active.

    extension ViewController: UISearchBarDelegate {
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            // Check if the searched text has at least 1 character otherwise show all results
            guard searchText != "" else {
                isSearching = false
                searchedResults.removeAll()
                return
            }
    
            searchedResults = filteredUniversities(query: searchText)
            isSearching = true
        }
    }
    

    And we use the UISearchBarDelegate to determine when the user types something into the search bar.

    See full code here.

    Login or Signup to reply.
  2. This is probably what you want https://developer.apple.com/documentation/uikit/uinavigationitem/2897305-searchcontroller
    When you’ve got your UITableView working I’d also recommend switching to UICollectionView lists see here. https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views

    FWIW UICollectionViewController is usually fine, the automatic deselection of cells in coordination with UINavigationController is mostly broken, so just do it yourself, it’s easy enough to do.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search