infernouk infernouk - 19 days ago 4
Swift Question

Filtering Array and displaying in Table View?

I want to search an dictionary of exercises for the name key and then show the filtered result in the table view. I am using this function

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
let filtered = exercises.filter { $0["name"] == searchText }
print(filtered)

if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.exercisesTableView.reloadData()
}


Variables:

var exercises = [Exercise]()
var filtered: [NSMutableArray] = []
var searchActive: Bool = false


In the search function I get the error


Type'Exercise' has no subscript members


and then i have the issue that the result is an NSMutableArray and so I cant set the result names as cell text to display


Cannot convert value of type 'NSMutableArray' to type 'String' in coercion


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if (searchActive){
cell.textLabel?.text = filtered[indexPath.row] as String
} else {
let exercise = exercises[indexPath.row]

cell.textLabel!.text = exercise.name
}
return cell
}


Here is my Exercise dictionary for reference:

final public class Exercise {
var id: Int
var descrip: String
var name: String
var muscles: [Int]
var equipment: [Int]

public init?(dictionary: [String: Any]) {

guard
let id = dictionary["id"] as? Int,
let descrip = dictionary["description"] as? String,
let name = dictionary["name"] as? String,
let muscles = dictionary["muscles"] as? [Int],
let equipment = dictionary["equipment"] as? [Int]

else { return nil }

self.id = id
self.descrip = descrip
self.name = name
self.muscles = muscles
self.equipment = equipment

}


I can fix the second error by making var filtered: [String] = [] so it can be used as a cell title, but that doesnt resolve the first error and im not sure is the right way to go about it?

Answer

Your filtered also type of [Exercise] and you need to filter it like.

var filtered = [Exercise]() 

self.filtered = exercises.filter { $0.name == searchText }

Here $0 is type of Exercise object, so you need to access its property name using $0.name.

Edit: If you want filtered as type of [String] with only name then you can need to use both map and filter like this.

self.filtered = exercises.filter { $0.name == searchText }.map { $0.name }

OR

self.filtered = exercises.map { $0.name }.filter { $0 == searchText }

OR directly using filterMap as @dfri suggested.

self.filtered = exercises.flatMap{ $0.name == searchText ? $0.name : nil }
Comments