Jan Swoboda
Jan Swoboda

Reputation: 172

Filter TableView, depending on UISearchBar input (Swift)

What I want to do: I want to filter the TableViewCells that have a text on them, depending on the user input in the UISearchBar.

My problem: I got it to work with simple Cells. But now I use custom ones that I configure with a struct and now I have no clue how to filter them.

Here is my code:

import UIKit
import Firebase

class searchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
    
    @IBOutlet var searchy: UISearchBar!
    @IBOutlet var tabley: UITableView!
    
    var searchingNames = [String()]
    var searching = false
    var datas = [UserSearch]()

    override func viewDidLoad() {
        super.viewDidLoad()
        tabley.delegate = self
        tabley.dataSource = self
        searchy.delegate = self
        populateSearch()
        tabley.register(searchTableViewCell.nib(), forCellReuseIdentifier: searchTableViewCell.identifier)
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        if searching == true {
            return searchingNames.count
        } else{
            return datas.count
        }
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if searching == true {
            let post = datas[indexPath.row]
            let cell = tableView.dequeueReusableCell(withIdentifier: searchTableViewCell.identifier, for: indexPath) as! searchTableViewCell
            cell.configure(with: post)
            return cell
        } else{
            let post = datas[indexPath.row]
            let cell = tableView.dequeueReusableCell(withIdentifier: searchTableViewCell.identifier, for: indexPath) as! searchTableViewCell
            cell.configure(with: post)
            return cell
        }
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        
        searchingNames = datas.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()}) // Cannot assign value of type '[UserSearch]' to type '[String]'
            // Value of type 'UserSearch' has no member 'lowercased'
        searching = true
        tabley.reloadData()
    }
}

struct UserSearch {
    var id: String
    var name: String
    var pfp: String
}

Upvotes: 1

Views: 123

Answers (1)

vadian
vadian

Reputation: 285069

You have to filter a string property of UserSearch for example the name.

And you have to consider that the user clears the search field to reset searching to false

And there is a more efficient API to check for a substring


First of all the array of the search results must be the same type as the data source array

var searchingNames = [UserSearch]()

Replace textDidChange with

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    
   if searchText.isEmpty {
      searchingNames.removeAll()
      searching = false
   } else {
      searchingNames = datas.filter{ $0.name.range(of: searchText, options: [.anchored, .caseInsensitive]) != nil}
      searching = true
   }
   tabley.reloadData()
}
  • .anchored searches from the beginning of the string
  • .caseInsensitive is self-explanatory.

PS: In cellForRow is a mistake. In the searching == true scope replace

let post = datas[indexPath.row]

with

 let post = searchingNames[indexPath.row]

You can even reduce the code to

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let post = searching ? searchingNames[indexPath.row] : datas[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: searchTableViewCell.identifier, for: indexPath) as! searchTableViewCell
    cell.configure(with: post)
    return cell
}

Upvotes: 2

Related Questions