UISearchBar:传递数据;单击的标题与 ListViewController - Swift 中显示的数据不对应

Posted

技术标签:

【中文标题】UISearchBar:传递数据;单击的标题与 ListViewController - Swift 中显示的数据不对应【英文标题】:UISearchBar: passing data; Title that is clicked on does not correspond with data that is shown in ListViewController - Swift 【发布时间】:2020-10-17 21:09:33 【问题描述】:

我的 UISearchBar 目前有问题。因此,当我搜索一个单词时,UISearchBar 返回与我输入的字母/单词匹配的数据。但是,当我单击其中一个 tableview 单元格时,(标题)数据与 ListViewController 中显示的(项目)数据不对应。它所显示的(在 ListViewController 中)是与 tableView 的原始顺序/布局(索引)相对应的(项目)数据。因此,在搜索后,如果我单击与我搜索的内容匹配的第一个 tableView 单元格的(标题),它会显示(titledata)数组中第一个(字符串)的(项目)数据,而不是对应于标题显示。

例如: 如果我在我的 SearchBar New Haven(索引 1)和 New York(索引 2)中输入“New”。但是,当我单击(标题)New Haven tableView 单元格时,它会将我带到 Ann Arbor 的(项目)数据(原始布局的第一个索引)

谢谢!

结构代码:

struct Category 
   let title: String
   let items: [String]

数据(数组:派生自Struct)代码:

let data: [Category] = [
   Category(title: "Ann Arbor", items: ["Ann Arbor is a city located in Michigan.", "Population: 119,000","University: University of Michigan is located in Ann Arbor.",]),
   Category(title: "Los Angeles", items: ["Los Angeles is a city located in California.", "Population: 3,900,000,", "University: University of California of Los Angeles",]),
   Category(title: "New Haven", items: ["New Haven is a city located in Connecticut.", "Population: 130,000 ","University: Yale University",]),
   Category(title: "New York City", items: ["New York City is located in New York.", "Population: 8,300,000","University: Columbia University",]),
   Category(title: "San Fransisco", items: ["Ann Arbor is a city located in Michigan.", "Population: 881,000","University: University of San Francisco",]),
]

titledata(数组)代码:

let titledata = ["Ann Arbor", "Los Angeles","New Haven", "New York City", "San Fransisco"]

filteredData 变量:

 var filteredData: [String]!

在 viewDidLoad 函数中:

filteredData = titledata

注意:在 Storyboard 中链接的 SearchBar 委托。

UISearchBar 代码:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 
    
    filteredData = []
    
    if searchText == "" 
        
        filteredData = titledata
    
    
    else 
    for info in titledata 
        
        if info.lowercased().contains(searchText.lowercased()) 
            
            
            self.tableView.reloadData()
            filteredData.append(info)
            
            self.tableView.reloadData()
            
            
        
    
    self.tableView.reloadData()

didSelectRowAt 函数:

 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 

    let category = data[indexPath.row]
    let vc = ListViewController(items: category.items)
    vc.title = category.title
    self.navigationController?.pushViewController(vc, animated: true)
  

numberOfRowsInSection 函数:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return filteredData.count

cellForRowAt 函数:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
   let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
   cell.myLabel.text = filteredData[indexPath.row]
   cell.myImg.image = UIImage(named: filteredData[indexPath.row] + ".png")
   return cell

【问题讨论】:

【参考方案1】:

首先将数据源数组声明为非可选的空数组。

编辑:您的数据源应该是[Category] 而不是[String]

var filteredData = [Category]()

viewDidLoad 分配data 中,不需要titledata 数组。删除它。

filteredData = data

由于filteredData 是数据源数组,您必须从didSelectRowAt 中的该数组中获取项目

let category = filteredData[indexPath.row]

还有一些可以优化的东西。 在textDidChange 中,过滤数据的方式非常昂贵,因为循环和 - 更糟糕的是 - 在每次迭代中重新加载表视图。

这样效率更高

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 
    if searchText.isEmpty 
        filteredData = data
     else 
        filteredData = data.filter$0.title.range(of: searchText, options: .caseInsensitive) != nil 
    
    self.tableView.reloadData()

并将cellForRowAt替换为

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
   let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
   let title = filteredData[indexPath.row].title
   cell.myLabel.text = title
   cell.myImg.image = UIImage(named: title + ".png")
   return cell

如果您喜欢漂亮的动画,请使用 UITableViewDiffableDataSource,它会在数据源数组更改时为表格视图设置动画

【讨论】:

您好,感谢您的回复。现在我已将 let category = data[indexPath.row] 更改为: let category = filteredData[indexPath.row] 我收到错误消息,“让 vc 上的“'String' 类型的值没有成员 'items'” = ListViewController(items: category.items)" 代码行(在 didSelectRowAt 函数中)。再次感谢。 您的设计令人困惑。如果您需要类别,您的数据源数组必须是 var filteredData = [Category]() 您好,再次感谢您的回复。我已经尝试进行上面的编辑,现在我在 3 行代码中遇到了同样的错误:“无法将类型 '[String]' 的值分配给类型 '[Category]'(注意:我已经将我的 searchBar 配置更改为您的)。我的应用程序的整个目标是在 tableView 中显示(标题)数据,并能够单击 tableView 单元格并让它在我设置的 ListViewController 中显示(项目)数据. 如果有更有效的方法来做到这一点,我很乐意适应。谢谢! 嗨 vadian,非常感谢您在这里与我合作。我已经进行了这些编辑,现在在 searchBar 配置中收到以下错误:无法推断成员'caseInsensitive'的上下文基础&'Category'类型的值没有成员'range' 两个错误都在以下代码行中:filteredData = data.filter$0.range(of searchText, options: .caseInsensitive) !=nil 【参考方案2】:

问题在于您的方法didSelectRowAt,您正在使用filteredData 数组来显示项目,但是当您在单元格上执行点击时,您使用的是不同的数组:

let category = data[indexPath.row]

当您在单元格上执行点击时,您还需要使用过滤数组:

let category = filteredData[indexPath.row]

【讨论】:

如上所述,现在我已将 let category = data[indexPath.row] 更改为:let category = filteredData[indexPath.row] 我收到错误消息“'String' 类型的值在“let vc = ListViewController(items: category.items)”代码行(在 didSelectRowAt 函数中)没有成员“项目”。谢谢!

以上是关于UISearchBar:传递数据;单击的标题与 ListViewController - Swift 中显示的数据不对应的主要内容,如果未能解决你的问题,请参考以下文章

单击 UISearchBar 的取消按钮后,如何使用 UISearchBar 刷新我的 UITableView?

NavigationItem + UISearchBar 与 Swift

当我在 NavigationBar 中单击 UISearchBar 时没有任何反应

iPhone UITableView 与 UISearchBar 和刷新部分索引

iOS:带有 UISearchdisplaycontroller 的 UISearchBar 通过单击搜索栏崩溃

UISearchBar 在搜索没有结果时显示标签,但在单击 UISearchBar 中的 x 时不会再次隐藏标签