iOS15 SwiftUI下如何正确过滤SectionedFetchRequest实现搜索功能
解决方案
你完全不需要实现复杂的RandomAccessCollection协议,只要构造一个轻量的临时结构体承接过滤后的分栏数据即可,十几行代码就能解决问题:
- 首先定义一个仅用于展示的分栏结构体,遵守
Identifiable协议即可满足ForEach的使用要求:
struct FilteredSection: Identifiable { let id: String let items: [Item] }
- 修改你的过滤方法,返回上述结构体数组:
private func getFilteredSections() -> [FilteredSection] { let cleanedFilter = searchText.trimmingCharacters(in: .whitespacesAndNewlines) guard !cleanedFilter.isEmpty else { // 搜索内容为空时直接返回原始数据映射结果 return mySections.map { section in FilteredSection(id: section.id, items: section.map { $0 }) } } func checkItem(_ item: Item) -> Bool { return item.name.localizedCaseInsensitiveContains(cleanedFilter) } return mySections.compactMap { section in // 先过滤当前分栏下符合搜索条件的条目 let matchedItems = section.filter(checkItem) // 没有符合条件的条目时直接丢弃当前分栏 guard !matchedItems.isEmpty else { return nil } return FilteredSection(id: section.id, items: matchedItems) } }
- 替换原有List的数据源即可,布局逻辑不需要做任何改动:
List { ForEach(getFilteredSections()) { section in Section(header: Text(section.id)) { // 如果你的Item未遵守Identifiable,这里改为ForEach(section.items, id: \.objectID) ForEach(section.items) { item in Text(item.name) } } } } .searchable(text: $searchText)
方案优势
- 完全避开了修改
SectionedFetchRequest谓词触发的视图重初始化问题,搜索状态保存在当前视图的@State变量中,跳转详情页返回后不会丢失,也不会出现详情页意外弹出的问题 - 代码复杂度极低,不需要适配任何系统底层协议
- 保留了原有分栏的id属性,完全不影响原有分栏标题的展示逻辑
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

