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

Posted

技术标签:

【中文标题】过滤数组并在表格视图中显示?【英文标题】:Filtering Array and displaying in Table View? 【发布时间】:2016-11-14 12:02:11 【问题描述】:

我想在练习字典中搜索名称键,然后在表格视图中显示过滤后的结果。我正在使用这个功能

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

在搜索功能中出现错误

Type'Exercise' 没有下标成员

然后我遇到的问题是结果是 NSMutableArray,因此我无法将结果名称设置为要显示的单元格文本

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    if (searchActive)
        cell.textLabel?.text = filtered[indexPath.row] as String
     else 
        let exercise = exercises[indexPath.row]

        cell.textLabel!.text = exercise.name
    
    return cell

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

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 filters: [String] = [] 来修复第二个错误,这样它就可以用作单元格标题,但这并不能解决第一个错误,而且我不确定这样做是否正确?

【问题讨论】:

【参考方案1】:

您的filtered 也是[Exercise] 的类型,您需要对其进行过滤。

var filtered = [Exercise]() 

self.filtered = exercises.filter  $0.name == searchText 

这里$0Exercise 对象的类型,因此您需要使用$0.name 访问其属性名称。

编辑:如果您希望filtered 是只有名称的[String] 类型,那么您可以像这样同时使用mapfilter

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

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

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

self.filtered = exercises.flatMap $0.name == searchText ? $0.name : nil 

【讨论】:

谢谢你,但是如果我将过滤设置为也 = [Exercise]() 当它不再是字符串时,我如何将它映射到单元格名称?看到我的代码部分 cell.textLabel?.text = filters[indexPath.row] as String 我试过了,但它不喜欢它,我需要编辑变量还是只插入规定的代码?错误是无法将“String”类型的值转换为闭包结果类型“Exercise”,并且在表格单元格名称语句中:无法将“Exercise”类型的值转换为强制类型“String” @NiravD 请注意,使用链式 filtermap 操作的常见替代方法是单个 flatMap 操作:self.filtered = exercises.flatMap $0.name == searchText ? $0.name : nil @infernouk 是的,现在您需要将filtered 更改为[String] 已正确写入Edit 行检查。 感谢我删除了控制器并制作了插座!【参考方案2】:

我昨天告诉过你忘记字典语义时使用自定义类。 不要使用键下标!

正如其他答案中提到的,您必须将filtered 也声明为[Exercise]

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] 类型,因此您必须以这种方式更改 cellForRowAtIndexPath

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

【讨论】:

谢谢我试过了,因为保持过滤器类型相同似乎更干净,没有错误只是我在 Nirav 的响应 cmets 中提到的在搜索栏中输入字母时仍然遇到这种奇怪的崩溃 你在使用UISearchController吗?如果是,请使用 searchResultController.isActive 检查搜索状态,而不是自定义布尔变量。 所以我需要将 searchResultController 声明为变量?只是将其换成 searchResultController.isActive 会导致未解决的标识符错误。我现在让 searchController = UISearchController(searchResultsController: nil) 是的,当然var searchResultController: UISearchController! 但是你也应该使用updateSearchResults(for 而不是textDidChange 我已经更新到 searchResultController.isActive 但是现在这会导致致命的崩溃,只是在输入之前单击搜索字段。要更改为 updateSearchResults,它如何适合 textDidChange 语句? func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)【参考方案3】:

这里的问题是$0["name"] == searchText$0 在这种情况下属于 Excersise 类型,您将其称为数组。此行应如下所示:

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

【讨论】:

【参考方案4】:

就我而言,我在一些个人项目中使用了以下代码,代码与之前的答案非常相似。我只使用contains

func filter(query: String)
        if query.isEmpty 
            self.filteredData = self.originalData
         else 
            self.filteredData = self.originalData.filter 
                $0.prop1!.lowercased().contains(query)
            
        
    

【讨论】:

【参考方案5】:

清洁有效的方法

在你的类中声明这些数组:

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]

【讨论】:

以上是关于过滤数组并在表格视图中显示?的主要内容,如果未能解决你的问题,请参考以下文章

谁能告诉我为啥我的过滤数组是空的?

Swift UITableView(无部分)过滤到带有部分的表格视图

单击过滤器选项时,帖子/图像重叠,并在窗口调整大小后显示在砖石视图中

在 Tableview 中创建搜索字段

UISearchbar 并在查看控制器 xcode swift 中传递数据

使用导致崩溃的搜索结果更新表视图