问题描述
我像这样初始化这个赛道列表:
var tracks: [Track] = tracksData
并像这样实现搜索:
NavigationSearch(text: $searchText,searchResultsContent: {
vstack(alignment: .leading) {
Text("Search Results for \(searchText)")
.fontWeight(.bold)
.padding([.top,.bottom])
Divider()
ForEach(Track.filter { self.searchText.isEmpty ? true : $0.contains(self.searchText) },id: \.self) { fruit in
Text(fruit)
Divider()
}
Spacer()
}
.padding()
})
这是 Mark van Wijnen 的 medium article
但我总是收到如下所示的错误:
我知道错误是由我用于轨道对象的数据类型引起的,因为 Mark van Wijnen 使用了一个简单的字符串数组,但我无法修复此搜索功能,以便它能够搜索我的对象数组。我希望有人能帮助我解决这个问题。 提前致谢
链接到包含示例数据的包: https://workupload.com/file/cbky5ucgM26
解决方法
你离我太近了!将代码分开会产生更好的错误,你会发现它。如果使用 self 作为 id,则 ForEach 要求项目是可散列的。在 self 中使用 Track 的 id 属性可能会清除该错误。但是,需要一些工作才能实现,所以这里是重构的代码。
将搜索过滤器拆分到 TrackModel 中,以便可以搜索多个字段:
func search(_ query: String) -> Bool {
let searchable = [title,headline,description] + details
return searchable.filter({ $0.contains(query) }).count > 0
}
接下来在TrackView3中添加一个计算属性来封装列表:
var filtered : [Track] {
if searchText.isEmpty {
return tracks
} else {
return tracks.filter({ $0.search(searchText) })
}
}
现在 ForEach 没有所有的搜索内容及其整洁的形式:
ForEach(filtered,id: \.id) { track in
TrackDetailView(tracks: track)
Divider()
}
Paul Hudson 最近制作了一个视频,其中提供了更好的 Swift Views 技巧。他介绍了在计算属性中封装代码。它使代码更清晰,并使编码人员免受声明树中的错误(错误并不总是有帮助)。 5 Steps to Better SwiftUI Views