UISearchBar: passing data between ViewControllers; Title that is clicked on does not correspond with data that is shown in ListViewController (Swift)

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
}

It is good to post code, it would be better to format to make it easier to read:
  • paste with Paste and Match Style

  • use the code formatter tool (<>)

  • remove unnecessary empty lines

This also allows to reference code by line.

Code Block
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
}


It seems to be doing what you asked for:
  • indexPath.row is 0 (you click on the first displayed row)

  • you use data and not filtered Data, hence you get Ann Arbor.

Change line 62 into
Code Block
let category = filteredData[indexPath.row]

Hi,

Thank you for the response. I will make sure to use the code formatter tool next time I post a question.

Now that I have changed line 62 from:
Code Block Swift
let category = data[indexPath.row]

to:
Code Block Swift
let category = filteredData[indexPath.row]


I am getting the error, "Value of type 'String' has no member 'items'" on line 63.

Thanks again.

OK, I did not notice that data and filteredData are not the same type (the naming is misleading).

So, you need a bit more care here:

Code Block
func tableView( tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let title = filteredData[indexPath.row] // with row == 0, that should be New Haven (index 0 and not 1)
// Find which data it is
let index = data.firstIndex{$0.title == title} ?? 0
let category = data[index]
let vc = ListViewController(items: category.items)
vc.title = category.title
self.navigationController?.pushViewController(vc, animated: true)
}

I have since resolved this issue, thanks.
  • This thread may now be locked.

How did you solve it ?

If this is by using my answer, just mark it as correct answer to close the thread.

Good continuation.
UISearchBar: passing data between ViewControllers; Title that is clicked on does not correspond with data that is shown in ListViewController (Swift)
 
 
Q