Swift 过滤数组并在表视图中显示?

Swift 过滤数组并在表视图中显示?,swift,uitableview,uisearchbar,Swift,Uitableview,Uisearchbar,我想在练习字典中搜索name键,然后在表视图中显示过滤结果。我正在使用这个函数 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { let filtered = exercises.filter { $0["name"] == searchText } print(filtered) if(filtered.count == 0){ searchActi

我想在练习字典中搜索name键,然后在表视图中显示过滤结果。我正在使用这个函数

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()
}
变量:

var exercises = [Exercise]()
var filtered: [NSMutableArray] = []
var searchActive: Bool = false
在搜索函数中,我得到了错误

类型“Exercise”没有下标成员

然后我有一个问题,结果是一个NSMutableArray,因此我不能将结果名称设置为要显示的单元格文本

无法在强制中将“NSMutableArray”类型的值转换为“String”类型

这是我的练习词典供参考:

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

    }

我可以通过使var filtered:[String]=[]来修复第二个错误,这样它就可以用作单元格标题,但这并不能解决第一个错误,我不确定是正确的解决方法?

这里的问题是
$0[“name”]==searchText
<代码>$0在此上下文中是
EXERSISE
类型,您将其称为数组。这一行应该如下所示:


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

您的
已筛选的
类型也包括
[Exercise]
,您需要像这样进行筛选

var filtered = [Exercise]() 

self.filtered = exercises.filter { $0.name == searchText }
这里的
$0
Exercise
对象的类型,因此您需要使用
$0.name
访问其属性名称

编辑:如果您想将
过滤后的
作为
[String]
的类型,并且只使用名称,那么您可以像这样同时使用
映射
过滤

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

或者直接使用@dfri建议的
filterMap

self.filtered = exercises.flatMap{ $0.name == searchText ? $0.name : nil }
我昨天告诉过您,在使用自定义类时忘记字典语义。
不要使用密钥订阅

如其他答案所述,您必须声明
已过滤
也为
[练习]

var filtered = [Exercise]() 
和过滤器

self.filtered = exercises.filter { $0.name == searchText }
但是,如果要同时搜索部分字符串,请使用

self.filtered = exercises.filter {$0.name.range(of: searchText, options: [.anchored, .caseInsensitive, .diacriticInsensitive]) != nil }
但是

由于筛选数组和未筛选数组都属于
[Exercise]
类型,因此必须以这种方式更改
cellforrowatinexpath

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

在我的例子中,我在一些个人项目中使用了以下代码,代码与前面的答案非常相似。我只是使用
包含

func filter(query: String){
        if query.isEmpty {
            self.filteredData = self.originalData
        } else {
            self.filteredData = self.originalData.filter {
                $0.prop1!.lowercased().contains(query)
            }
        }
    }
清洁有效的方法 在类中声明以下数组:

var filteredData: [Exercise] = []  
{
    didSet
    { 
        tableView.reloadData()
    }
}

// once we get our data, we will put it into filtered array
// user will interact only with filtered array
var source: [Exercise] = [] 
{
    didSet
    { 
        filteredData = source
    }
}
按如下方式实现您的功能:

extension ViewController: UISearchBarDelegate
{
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
    {        
        let searchText = searchText.lowercased()
        let filtered = source.filter({ $0.lowercased().contains(searchText) })
        filteredData = filtered.isEmpty ? source : filtered
    }
}
您将注意到,用户将永远不会与原始数组交互,而是与过滤后的数组交互

// MARK: UITableViewDataSource

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

// MARK: UITableViewDelegate

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    .
    .

    cell.textLabel?.text = filteredData[indexPath.row]
}

谢谢,但是如果我将filtered设置为也=[Exercise](),当它不再是字符串时,如何将它映射到单元格名称?请参阅我的代码单元格.textLabel?.text=filtered[indexPath.row]的一部分,因为我尝试了这个方法,但它不喜欢,我是否也需要编辑变量,还是只插入指定的代码?错误为无法将“String”类型的值转换为闭包结果类型“Exercise”,并且在表单元格名称语句中:无法将“Exercise”类型的值转换为中的“String”类型coercion@NiravD请注意,使用链式
过滤器
映射
操作的常见替代方法是单个
flatMap
操作:
self.filtered=exercises.flatMap{$0.name==searchText?$0.name:nil}
@infernouk是的,现在您需要更改
filtered
,因为
[String]
已经写入
编辑
行检查正确。谢谢,我删除了控制器并打开了插座,使它工作正常!谢谢,我尝试过这个方法,因为它看起来更干净,可以保持过滤器的类型不变,没有错误,只是当我在Nirav的回复评论中提到在搜索栏中键入一封信时,仍然会遇到这种奇怪的崩溃。您是否使用
uisearch controller
?如果是,请使用
searchResultController.isActive
检查搜索状态,而不是自定义布尔变量。因此,我需要将searchResultController声明为变量?仅将其替换为searchResultController.isActive会导致无法解决的标识符错误。我让searchController=UISearchController(searchResultController:nil),当然
var searchResultController:UISearchController但是您还应该使用
updateSearchResults(对于
而不是
textDidChange
我已更新为searchResultController.isActive,但这现在会导致致命的崩溃,只需在键入之前单击搜索字段。对于更改为updateSearchResults,它如何适应textDidChange语句?func searchBar(uSearchBar:UISearchBar,textDidChange searchText:String)
extension ViewController: UISearchBarDelegate
{
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
    {        
        let searchText = searchText.lowercased()
        let filtered = source.filter({ $0.lowercased().contains(searchText) })
        filteredData = filtered.isEmpty ? source : filtered
    }
}
// MARK: UITableViewDataSource

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

// MARK: UITableViewDelegate

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    .
    .

    cell.textLabel?.text = filteredData[indexPath.row]
}