Swift 过滤数组并在表视图中显示?
我想在练习字典中搜索name键,然后在表视图中显示过滤结果。我正在使用这个函数Swift 过滤数组并在表视图中显示?,swift,uitableview,uisearchbar,Swift,Uitableview,Uisearchbar,我想在练习字典中搜索name键,然后在表视图中显示过滤结果。我正在使用这个函数 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { let filtered = exercises.filter { $0["name"] == searchText } print(filtered) if(filtered.count == 0){ searchActi
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
let filtered = exercises.filter { $0["name"] == searchText }
print(filtered)
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.exercisesTableView.reloadData()
}
变量:
var exercises = [Exercise]()
var filtered: [NSMutableArray] = []
var searchActive: Bool = false
在搜索函数中,我得到了错误
类型“Exercise”没有下标成员
然后我有一个问题,结果是一个NSMutableArray,因此我不能将结果名称设置为要显示的单元格文本
无法在强制中将“NSMutableArray”类型的值转换为“String”类型
这是我的练习词典供参考:
final public class Exercise {
var id: Int
var descrip: String
var name: String
var muscles: [Int]
var equipment: [Int]
public init?(dictionary: [String: Any]) {
guard
let id = dictionary["id"] as? Int,
let descrip = dictionary["description"] as? String,
let name = dictionary["name"] as? String,
let muscles = dictionary["muscles"] as? [Int],
let equipment = dictionary["equipment"] as? [Int]
else { return nil }
self.id = id
self.descrip = descrip
self.name = name
self.muscles = muscles
self.equipment = equipment
}
我可以通过使var filtered:[String]=[]来修复第二个错误,这样它就可以用作单元格标题,但这并不能解决第一个错误,我不确定是正确的解决方法?这里的问题是
$0[“name”]==searchText
<代码>$0在此上下文中是EXERSISE
类型,您将其称为数组。这一行应该如下所示:
let filtered=exercises.filter{$0.name==searchText}
您的已筛选的类型也包括[Exercise]
,您需要像这样进行筛选
var filtered = [Exercise]()
self.filtered = exercises.filter { $0.name == searchText }
这里的$0
是Exercise
对象的类型,因此您需要使用$0.name
访问其属性名称
编辑:如果您想将过滤后的作为[String]
的类型,并且只使用名称,那么您可以像这样同时使用映射
和过滤
self.filtered = exercises.filter { $0.name == searchText }.map { $0.name }
或
或者直接使用@dfri建议的filterMap
self.filtered = exercises.flatMap{ $0.name == searchText ? $0.name : nil }
我昨天告诉过您,在使用自定义类时忘记字典语义。
不要使用密钥订阅
如其他答案所述,您必须声明已过滤
也为[练习]
var filtered = [Exercise]()
和过滤器
self.filtered = exercises.filter { $0.name == searchText }
但是,如果要同时搜索部分字符串,请使用
self.filtered = exercises.filter {$0.name.range(of: searchText, options: [.anchored, .caseInsensitive, .diacriticInsensitive]) != nil }
但是
由于筛选数组和未筛选数组都属于[Exercise]
类型,因此必须以这种方式更改cellforrowatinexpath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let exercise : Exercise
if (searchActive){
exercise = filtered[indexPath.row]
} else {
exercise = exercises[indexPath.row]
}
cell.textLabel!.text = exercise.name
return cell
}
在我的例子中,我在一些个人项目中使用了以下代码,代码与前面的答案非常相似。我只是使用包含
func filter(query: String){
if query.isEmpty {
self.filteredData = self.originalData
} else {
self.filteredData = self.originalData.filter {
$0.prop1!.lowercased().contains(query)
}
}
}
清洁有效的方法
在类中声明以下数组:
var filteredData: [Exercise] = []
{
didSet
{
tableView.reloadData()
}
}
// once we get our data, we will put it into filtered array
// user will interact only with filtered array
var source: [Exercise] = []
{
didSet
{
filteredData = source
}
}
按如下方式实现您的功能:
extension ViewController: UISearchBarDelegate
{
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
let searchText = searchText.lowercased()
let filtered = source.filter({ $0.lowercased().contains(searchText) })
filteredData = filtered.isEmpty ? source : filtered
}
}
您将注意到,用户将永远不会与原始数组交互,而是与过滤后的数组交互
// MARK: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return filteredData.count
}
// MARK: UITableViewDelegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
.
.
cell.textLabel?.text = filteredData[indexPath.row]
}
谢谢,但是如果我将filtered设置为也=[Exercise](),当它不再是字符串时,如何将它映射到单元格名称?请参阅我的代码单元格.textLabel?.text=filtered[indexPath.row]的一部分,因为我尝试了这个方法,但它不喜欢,我是否也需要编辑变量,还是只插入指定的代码?错误为无法将“String”类型的值转换为闭包结果类型“Exercise”,并且在表单元格名称语句中:无法将“Exercise”类型的值转换为中的“String”类型coercion@NiravD请注意,使用链式过滤器
和映射
操作的常见替代方法是单个flatMap
操作:self.filtered=exercises.flatMap{$0.name==searchText?$0.name:nil}
@infernouk是的,现在您需要更改filtered
,因为[String]
已经写入了编辑
行检查正确。谢谢,我删除了控制器并打开了插座,使它工作正常!谢谢,我尝试过这个方法,因为它看起来更干净,可以保持过滤器的类型不变,没有错误,只是当我在Nirav的回复评论中提到在搜索栏中键入一封信时,仍然会遇到这种奇怪的崩溃。您是否使用uisearch controller
?如果是,请使用searchResultController.isActive
检查搜索状态,而不是自定义布尔变量。因此,我需要将searchResultController声明为变量?仅将其替换为searchResultController.isActive会导致无法解决的标识符错误。我让searchController=UISearchController(searchResultController:nil),当然var searchResultController:UISearchController代码>但是您还应该使用updateSearchResults(对于
而不是textDidChange
我已更新为searchResultController.isActive,但这现在会导致致命的崩溃,只需在键入之前单击搜索字段。对于更改为updateSearchResults,它如何适应textDidChange语句?func searchBar(uSearchBar:UISearchBar,textDidChange searchText:String)
extension ViewController: UISearchBarDelegate
{
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
let searchText = searchText.lowercased()
let filtered = source.filter({ $0.lowercased().contains(searchText) })
filteredData = filtered.isEmpty ? source : filtered
}
}
// MARK: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return filteredData.count
}
// MARK: UITableViewDelegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
.
.
cell.textLabel?.text = filteredData[indexPath.row]
}