Phrixus
Phrixus

Reputation: 1219

TableView how to filter certain cells from the table

In a UITableViewController class that is responsible to populate a TableView with cells, I want to filter some of the cells but I can't figure out how I would do that.

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return meals.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cellIdentifier = "MealTableViewCell"
       let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MealTableViewCell

       let meal = meals[indexPath.row]
       cell.title.text = meal.name

       return cell
}

I have the attribute meal.veg : Bool and ideally, I want to populate the TableView only with meals that are meal.veg == true. What I am stuck with, is that I can't really understand how the override func tableView() does populate the table. I mean how is this function called? And how can I filter the cells.

Because the return type of the function is UITableViewCell and is not Optional, I have to return a cell, which doesn't allow the chance for cell filtering.

Upvotes: 1

Views: 2769

Answers (3)

Matt Le Fleur
Matt Le Fleur

Reputation: 2856

Here's an example, with some extra suggestions :)

OK so let's say you've got a class, something like:

class Meal {
    var name: String
    var veg: Bool

    init(_ name: String, isVeg veg: Bool) {
        self.name = name
        self.veg = veg
    }
}

Then you have a load of meals in an array:

let carrots = Meal("Carrots", isVeg: true)
let steak = Meal("Steak & chips", isVeg: false)
let curry = Meal("Chicken korma", isVeg: false)
let sausage = Meal("Bangers and mash!", isVeg: false)
let salad = Meal("Spring asparagus salad", isVeg: true)

let meals = [carrots, steak, curry, sausage, salad]

What you want to do is filter those meals (based on whatever parameter you like).

var isFiltered = true
var filteredMeals = meals.filter { $0.veg }

Here you can see I've added a value (isFiltered) for whether you want to use the filter or not. (We'll see more why in a sec). Note also that the filteredMeals is in a separate array so that we don't lose our original data source, should we wish to remove or change the filter.

With your tableView you'd then set the numberOfRowsInSection and cellForRowAtIndexPath:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return isFiltered ? filteredMeals.count : meals.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellIdentifier = "MealTableViewCell"
    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MealTableViewCell

    let meal = isFiltered ? filteredMeals[indexPath.row] ? meals[indexPath.row]
    cell.title.text = meal.name

    return cell
}

So here you can see I'm making use of the isFiltered variable to determine whether I want to use the filtered results or not.

Upvotes: 4

Firatov
Firatov

Reputation: 53

Why don't you just filter the meals(outside of table view's datasource method) instead of cells and use the count of the filtered meals accordingly? Like:

let filteredMeals = meals.filter { $0.veg == true }

Upvotes: 1

Rajat
Rajat

Reputation: 11127

Problem - With UITableView, the method which is fired first is numberOfRowsInSection this will tell the TableView how many cell are there in the TableView, after getting the numbers the method cellForRowAtIndexPath will get fired which will used to design your TableView.

Now you are returning a count lets say 10 in numberOfRowsInSection out of which you just want to show 5 cell lets say those 5 are meal.veg == true, based on your filter meal.veg which is not possible as you need to return a cell from cellForRowAtIndexPath.

Solution - To resolve it, before reloading your table view you need to filter your array and filter out those results which are having a value meal.veg == true, then you need to pass the count of your filtered array in numberOfRowsInSection and as per that filtered array you can design your cell from cellForRowAtIndexPath

Upvotes: 2

Related Questions