3

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?

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

How about this?

var filteredFruits = fruits.filter ({ (fruitData: [String]) -> Bool in
    let fruit = fruitData[0]
    return fruit.lowercased().range(of: searchText.lowercased()) != nil
})

Comments

0

I see your code is too complicated, let keep everything is simple.

let fruits: [[String]] = [["Apple", "Green"],["Pear", "Green"], ["Banana", "Yellow"], ["Orange", "Orange"]]
var filteredFruits = [String]()
var shouldShowSearchResults = false

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    filteredFruits.removeAll()
    if searchText.isEmpty {
        // do something if searchText is empty
    } else {
        let arr = fruits.filter({ (fruit) -> Bool in
            return fruit[0].lowercased().contains(searchText.lowercased())
        })
        filteredFruits = arr.map({ (fruit) -> String in // convert [[String]] -> [String]
            return fruit[0]
        })
    }
    self.tableView.reloadData()
}

I think it'll be better if the type of filteredFruits as same as fruits's type. And instead of [[String]], you can declare an array of type or tuple like this let fruits: [(name: String, color: String)] = [(name: "Apple", color: "Green")]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.