Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS Swift Searching table from an Array

I have just started to learn swift and i am looking at the tableview and searchbar feature. Below i have my array which is a list of fruits:

var fruits: [[String]] = [["Apple", "Green"],["Pear", "Green"], ["Banana", "Yellow"], ["Orange", "Orange"]]

I have them in a table view with the name of the fruit as the title and the colour as a subtitle. I am trying to use the search bar to filter but i cant seem to get it right. I only want to search for the name of the fruit not the colour.

var filteredFruits = [String]()
var shouldShowSearchResults = false

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

    filteredFruits.removeAll()

    var i = 0
    while i < fruits.count
        {
            var filteredFruits = fruits[i].filter ({ (fruit: String) -> Bool in
                return fruit.lowercased().range(of: searchText.lowercased()) != nil
            })
            if searchText != ""
            {
                shouldShowSearchResults = true

                if filteredItems.count > 0
                {
                    filteredFruits.append(filteredItems[0])
                    filteredItems.removeAll()
                }
            }
            else
            {
                shouldShowSearchResults = false

            }

            i += 1
        }

    self.tableView.reloadData()
}

I do get results returned but it mixes up the subtitles and the titles as well as not returning the correct results. Can anyone point me in the right direction?

like image 219
user1854914 Avatar asked Sep 14 '26 15:09

user1854914


2 Answers

I do not understand why you iterate over the fruits using some kind of while loop. Instead I would propose you take advantage of a function like:

func filterFruits(searchText: String) -> [[String]] {
    guard searchText != "" else {
        return fruits
    }
    let needle = searchText.lowercased()
    return fruits.filter {fruitObj in
        return fruitObj.first!.lowercased().contains(needle)
    }
}

That function returns all fruits that have a name containing the searchText.

filterFruits(searchText: "g") yields [["Orange", "Orange"]]

If you want to search through all attributes use something like:

func filterFruits(searchText: String) -> [[String]] {
    guard searchText != "" else {
        return fruits
    }
    let needle = searchText.lowercased()
    return fruits.filter {fruitObj in
        return fruitObj.contains { attribute in
            attribute.lowercased().contains(needle)
        }
    }
}

filterFruits(searchText: "g") yields [["Apple", "Green"], ["Pear", "Green"], ["Orange", "Orange"]]

To get you on the right track for the future: you should really introduce a Fruit class which holds all relevant information of one specific fruit instance. Then you can use the first function and do something like fruitObj.matches(searchText) where you define a func inside the Fruit class which determines if the fruit matches the search.

like image 83
luk2302 Avatar answered Sep 17 '26 05:09

luk2302


How about this?

var filteredFruits = fruits.filter ({ (fruitData: [String]) -> Bool in
    let fruit = fruitData[0]
    return fruit.lowercased().range(of: searchText.lowercased()) != nil
})
like image 35
Sunil Chauhan Avatar answered Sep 17 '26 07:09

Sunil Chauhan