IOS Swift Searching table from an Array

2019-07-03 23:19发布

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条回答
霸刀☆藐视天下
2楼-- · 2019-07-04 00:00

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")]

查看更多
一纸荒年 Trace。
3楼-- · 2019-07-04 00:16

How about this?

var filteredFruits = fruits.filter ({ (fruitData: [String]) -> Bool in
    let fruit = fruitData[0]
    return fruit.lowercased().range(of: searchText.lowercased()) != nil
})
查看更多
4楼-- · 2019-07-04 00:18

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.

查看更多
登录 后发表回答