Swift中如何访问嵌套结构体属性供UISearchBar搜索使用
UITableView 嵌套结构体搜索问题排查与修复
问题场景
当前表格分2个分区展示嵌套结构体数据,结构体定义如下:
struct ReceiveInResponse: Codable { var result: [ReceiveIn] } struct ReceiveIn: Codable { var section: String var items: [ReceiveInComp] enum CodingKeys: String, CodingKey { case section = "Section" case items } } struct ReceiveInComp: Codable { let owner, barcode, quantity: String let resultDescription, status: String enum CodingKeys: String, CodingKey { case owner = "Owner" case barcode = "Barcode" case quantity = "Quantity" case resultDescription = "Description" case status = "Status" } }
实现barcode字段搜索时触发报错:Type '[ReceiveInComp]' has no member 'barcode',修复报错后又出现搜索结果重复的问题。
报错根因
两种错误写法的本质问题都是类型混淆:
ReceiveIn的items属性是[ReceiveInComp]类型,也就是ReceiveInComp元素组成的数组,barcode是数组内单个元素的属性,数组本身不存在这个属性,直接写myitems.barcode必然报错- 第一种写法用
switch .barcode是枚举关联值的匹配语法,myitems是数组类型,不是枚举,语法完全不适用 - 后续遍历item匹配时出现重复条目,是因为每匹配到一个符合条件的item就把整个分区对象追加到过滤列表,一个分区下如果有多个匹配item,同一个分区就会被多次添加,造成重复。
正确实现代码
根据展示需求二选一即可:
方案1:匹配到条目时保留整个分区的所有内容
只要分区下存在任意一个barcode匹配搜索词的条目,就把整个分区加入过滤列表,不会重复添加:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { self.filteredList.removeAll() let searchKeyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() // 搜索词为空时返回全量数据 guard !searchKeyword.isEmpty else { self.filteredList = self.ReviewList self.tableView.reloadData() return } for sectionItem in self.ReviewList { // 检查当前分区是否存在匹配项,只要有一个匹配就保留分区,仅追加一次 let isContainMatch = sectionItem.items.contains { comp in comp.barcode.lowercased().contains(searchKeyword) } if isContainMatch { self.filteredList.append(sectionItem) } } self.tableView.reloadData() }
方案2:搜索结果仅展示分区下匹配的条目
匹配时只保留分区内符合搜索条件的item,不展示同分区下的无关条目:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { self.filteredList.removeAll() let searchKeyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() guard !searchKeyword.isEmpty else { self.filteredList = self.ReviewList self.tableView.reloadData() return } for sectionItem in self.ReviewList { // 筛选当前分区下所有匹配的条目 let matchedComps = sectionItem.items.filter { comp in comp.barcode.lowercased().contains(searchKeyword) } // 有匹配项时才把处理后的分区加入列表,避免空分区、重复分区 if !matchedComps.isEmpty { var filteredSection = sectionItem filteredSection.items = matchedComps self.filteredList.append(filteredSection) } } self.tableView.reloadData() }
注意:如果
ReviewList里的ReceiveIn实例是let常量,方案2里需要把ReceiveIn的items属性从let改为var,或者自定义构造方法生成新的实例。
内容的提问来源于stack exchange,提问作者Mike Volmar
相关产品推荐
相关产品推荐

