I'm currently having an issue with my UISearchBar. So when I search for a word, the UISearchBar returns the data that matches the letter(s)/word that I typed. However, when I click one of the tableview cells, the (title) data does not correspond to the (items) data that is shown in the ListViewController. What it does display, (in the ListViewController) is the (items) data that corresponds to the original order/layout (index) of the tableView. So, after searching if I click on the (title) for the first tableView cell that matches what I searched, it displays the (items) data for the first (string) in the (titledata) array instead of corresponding to the title that is shown.
For example: If I type "New" into my SearchBar New Haven (index 1) & New York (index 2) pop up. But, when I click on the (title) New Haven tableView cell, it brings me to the (items) data of Ann Arbor (the first index of the original layout)
Thanks!
Struct Code:
struct Category {
let title: String
let items: [String]
}
Data (Array: derived from Struct) Code:
let data: [Category] = [
Category(title: "Ann Arbor", items: ["Ann Arbor is a city located in Michigan.", "Population: 119,000","University: University of Michigan is located in Ann Arbor.",]),
Category(title: "Los Angeles", items: ["Los Angeles is a city located in California.", "Population: 3,900,000,", "University: University of California of Los Angeles",]),
Category(title: "New Haven", items: ["New Haven is a city located in Connecticut.", "Population: 130,000 ","University: Yale University",]),
Category(title: "New York City", items: ["New York City is located in New York.", "Population: 8,300,000","University: Columbia University",]),
Category(title: "San Fransisco", items: ["Ann Arbor is a city located in Michigan.", "Population: 881,000","University: University of San Francisco",]),
]
titledata (Array) Code:
let titledata = ["Ann Arbor", "Los Angeles","New Haven", "New York City", "San Fransisco"]
filteredData var:
var filteredData: [String]!
in viewDidLoad func:
filteredData = titledata
Note: SearchBar Delegate linked in Storyboard.
UISearchBar Code:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = []
if searchText == "" {
filteredData = titledata
}
else {
for info in titledata {
if info.lowercased().contains(searchText.lowercased()) {
self.tableView.reloadData()
filteredData.append(info)
self.tableView.reloadData()
}
}
}
self.tableView.reloadData()
}
didSelectRowAt Func:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let category = data[indexPath.row]
let vc = ListViewController(items: category.items)
vc.title = category.title
self.navigationController?.pushViewController(vc, animated: true)
}
numberOfRowsInSection func:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
cellForRowAt func:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.myLabel.text = filteredData[indexPath.row]
cell.myImg.image = UIImage(named: filteredData[indexPath.row] + ".png")
return cell
}
First of all declare a data source array always as non-optional empty array.
Edit: Your data source is supposed to be
[Category]
rather than[String]
In
viewDidLoad
assigndata
, thetitledata
array is not needed. Delete it.As
filteredData
is the data source array you have to get the item from this array indidSelectRowAt
There are some other things which can be optimized. In
textDidChange
the way to filter the data is very expensive because of the loop and – worse – by reloading the table view in each iteration.This is much more efficient
And replace
cellForRowAt
withIf you like a nice animation use
UITableViewDiffableDataSource
which animates the table view on change of the data source array