SwiftUI网络数据应用添加searchable搜索栏过滤自定义对象问题
SwiftUI 自定义对象列表实现.searchable本地搜索
问题背景
这是Greg Lim所著《Beginning Swift UI》中调用Github Web接口的SwiftUI练习扩展项目,项目仓库地址:GitProbe。
项目在原有练习基础上做了改动:将原代码中硬编码的查询目标改为可手动输入的入口,支持用户自定义要查询的用户。由于接口返回数据量较大,需要给结果列表添加.searchable修饰符,支持用户过滤已拉取的列表结果。
现有实现参考了基础字符串列表的搜索方案,但接口返回的JSON会被解码为自定义User对象组成的数组,直接套用字符串匹配逻辑无法正常工作,原有代码存在逻辑错误,需要调整实现。
原有代码问题
你写的searchResults计算属性和列表绑定逻辑有两个明显错误:
- 搜索分支错误调用了
fetchUsers.search(for: searchText),这个方法是发起网络请求重新拉取Github接口数据的方法,不是本地列表过滤逻辑,完全不符合本地筛选的需求 - List组件的数据源仍然直接绑定了
fetchUsers.users,没有使用你定义的searchResults计算属性,所以搜索框输入内容不会触发列表内容刷新
修正实现
直接在searchResults计算属性中实现本地过滤逻辑,匹配User对象的对应属性即可,同时将List的数据源替换为searchResults,修正后的UserView代码如下:
struct UserView: View { @State var username: String @ObservedObject var fetchUsers = FetchUsers() @State var searchText = "" var body: some View { List { ForEach(searchResults, id:\.self) { user in NavigationLink(user.login, destination: UserDetailView(user:user)) } }.onAppear { self.fetchUsers.search(for: username) } .searchable(text: $searchText) .navigationTitle("Users") } /// 搜索结果计算属性 private var searchResults: [User] { let trimmedSearchText = searchText.trimmingCharacters(in: .whitespacesAndNewlines) if trimmedSearchText.isEmpty { // 搜索内容为空时返回全量拉取到的用户列表 return fetchUsers.users } else { // 本地匹配用户名,不区分大小写 return fetchUsers.users.filter { user in user.login.localizedCaseInsensitiveContains(trimmedSearchText) } } } }
扩展说明
- 上述实现用
localizedCaseInsensitiveContains做匹配,默认不区分大小写,符合常规搜索使用习惯,如果需要严格区分大小写,直接替换为contains即可 - 如果需要支持多字段搜索,比如同时匹配用户名和用户ID,只需要在filter闭包中添加或判断条件即可,示例:
return fetchUsers.users.filter { user in user.login.localizedCaseInsensitiveContains(trimmedSearchText) || String(user.id).contains(trimmedSearchText) } - 如果需要实现输入时实时请求Github接口的远程搜索,而不是过滤本地已拉取的数据,需要给
searchText添加onChange监听,加防抖处理后再调用网络请求方法,避免输入过程中频繁发起无效请求。
内容的提问来源于stack exchange,提问作者ethamoose
相关产品推荐
相关产品推荐

