You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在嵌套数组结构的UITableView中实现Sign内容搜索过滤?

问题描述

我定义了两个类:

class Sign {
    let code: String
    let name: String
    let description: String
    let picture: String
    
    init(code: String, name: String, description: String, picture: String) {
        self.code = code
        self.name = name
        self.description = description
        self.picture = picture
    }
}

class Category {
    let name: String
    let sign: [Sign]
    
    init(name: String, sign: [Sign]) {
        self.name = name
        self.sign = sign
    }
}

在UITableView中,我将Category作为分组标题(section title),Sign作为分组行(section row)展示。现在想在TableView上方添加SearchBar实现搜索功能,但目前仅能对Category名称进行过滤。我需要实现:当在搜索栏输入关键词(如"yy"或"y")时,TableView仅显示名称包含该关键词的Sign,同时保留其所属的Category作为分组标题。

示例:

var categories: [Category] = [
    Category(name: "X", sign: [Sign(code: "X-1", name: "***")]),
    Category(name: "Y", sign: [Sign(code: "Y-1", name: "Yyy")])
]

输入"yy"后,需仅显示名称含"yy"的Sign条目及其所属Category。

当前TableView配置代码:

override func numberOfSections(in tableView: UITableView) -> Int {
    return filteredCategories.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredCategories[section].sign.count
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch section {
    case 0:
        return filteredCategories[0].name
    case 1:
        return filteredCategories[1].name
    case 2:
        return filteredCategories[2].name
    case 3:
        return filteredCategories[3].name
    default:
        return "Error"
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.categorieCell, for: indexPath) as! SignTableViewCell
    let categorie = filteredCategories[indexPath.section]
    let sign = categorie.sign[indexPath.row]
    cell.signImagemin.image = UIImage(named: sign.picture)
    cell.signCodeMin.text = sign.code
    cell.signDescriptionMin.text = sign.name
    return cell
}

当前SearchBar实现代码:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    filteredCategories = []
    let text = searchText.lowercased()
    
    if searchText == "" {
        filteredCategories = categories
    } else {
        for categorie in categories {
            if categorie.name.lowercased().contains(searchText.lowercased()) {
                let signs = categorie.sign.filter() { $0.name.contains(searchText) }
                let newCat = categorie
                newCat.sign = signs
                
                filteredCategories.append(newCat)
            }
        }
    }
    
    self.tableView.reloadData()
}

需求效果:原本TableView展示完整的分组和行,输入关键词后,仅显示包含该关键词的Sign及其所属的Category分组标题。

解决方案

1. 修改Category类的属性

原Category类中sign是let常量,无法修改,需要改成var变量,这样才能创建过滤后的Sign数组并赋值:

class Category {
    let name: String
    var sign: [Sign]  // 将let改为var
    
    init(name: String, sign: [Sign]) {
        self.name = name
        self.sign = sign
    }
}

2. 修改搜索逻辑

当前代码只过滤了名称包含关键词的Category,现在需要改为:遍历每个Category,过滤出该Category下名称包含关键词的Sign;如果过滤后的Sign数组不为空,就创建一个新的Category实例(基于原Category,替换为过滤后的Sign数组),添加到filteredCategories中:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    filteredCategories = []
    let lowercasedText = searchText.lowercased()
    
    if searchText.isEmpty {
        filteredCategories = categories
    } else {
        for category in categories {
            // 过滤当前Category下名称包含关键词的Sign(忽略大小写)
            let filteredSigns = category.sign.filter {
                $0.name.lowercased().contains(lowercasedText)
            }
            // 仅当过滤后有Sign时,才添加该Category到结果集合
            if !filteredSigns.isEmpty {
                let filteredCategory = Category(name: category.name, sign: filteredSigns)
                filteredCategories.append(filteredCategory)
            }
        }
    }
    
    tableView.reloadData()
}

3. 优化TableView分组标题方法

原titleForHeaderInSection用switch判断section,扩展性差,直接通过section索引获取对应Category名称即可:

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    guard section < filteredCategories.count else {
        return "Error"
    }
    return filteredCategories[section].name
}

关键说明

  • 搜索时忽略大小写,提升关键词匹配的友好度;
  • 避免直接修改原Category的Sign数组,通过创建新实例的方式保证原始数据不被污染;
  • 只有包含符合条件Sign的Category才会出现在过滤结果中,确保界面仅展示有效内容。

内容的提问来源于stack exchange,提问作者krzychug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 01:25:21