使用 UISearchController 时如何删除排序/过滤的项目
Posted
技术标签:
【中文标题】使用 UISearchController 时如何删除排序/过滤的项目【英文标题】:How to delete sorted/filtered items when using UISearchController 【发布时间】:2020-05-29 03:13:03 【问题描述】:以下代码成功创建,在UITableView
中显示Cars
列表,您以后也可以在其中删除购物车。它还提供了一个UISearchController
,您可以在其中成功执行搜索。
我的问题是在搜索/过滤后尝试删除汽车,例如,如果用户搜索位于数组中间的汽车,它将在第一行显示正确的汽车但是如果他/她决定删除它,它将删除cars
数组中的第一项,因为过滤后的项始终位于filteredCars
数组的顶部。在这里我没有收到错误,但它不会从cars
数组中删除正确的项目,它总是从cars
数组中删除第一项。
代码如下:
型号
class Car
var make = ""
var model = ""
视图控制器
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating
var cars = Array<Car>()
var filteredCars = Array<Car>()
let searchController = UISearchController(searchResultsController: nil)
@IBOutlet weak var myTable: UITableView!
override func viewDidLoad()
super.viewDidLoad()
createCars()
filteredCars = cars
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search by model"
navigationItem.searchController = searchController
definesPresentationContext = true
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return filteredCars.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell")! as UITableViewCell
cell.textLabel?.text = filteredCars[indexPath.row].model
cell.detailTextLabel?.text = filteredCars[indexPath.row].make
return cell
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
let delete = UITableViewRowAction(style: .destructive, title: "Delete") action, index in
let alert = UIAlertController(title: "Delete selected car?", message: "This will permanently delete the selected car, do you want to continue?", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.destructive, handler: action in
self.filteredCars.remove(at: indexPath.row)
self.cars.remove(at: indexPath.row)
self.myTable.deleteRows(at: [indexPath], with: UITableView.RowAnimation.left)
))
self.present(alert, animated: true, completion: nil)
return [delete]
func updateSearchResults(for searchController: UISearchController)
if let searchText = searchController.searchBar.text
filteredCars = searchText.isEmpty ? cars : cars.filter((dataString: Car) -> Bool in
return dataString.model.lowercased().contains(searchText.lowercased())
)
myTable.reloadData()
// create cars manually for demonstration only
func createCars()
let car1 = Car()
car1.make = "Ford"
car1.model = "Explorer"
//... more cars here
cars.append(contentsOf: [car1, car2, car3, car4])
我尝试了以下操作,但一直收到 Index out of range
错误。
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
let delete = UITableViewRowAction(style: .destructive, title: "Delete") action, index in
let alert = UIAlertController(title: "Delete selected car?", message: "This will permanently delete the selected car, do you want to continue?", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.destructive, handler: action in
self.filteredCars.remove(at: indexPath.row)
self.myTable.deleteRows(at: [indexPath], with: UITableView.RowAnimation.left)
for i in 0..<self.cars.count
if self.cars[i].model == modelToDelete
self.cars.remove(at:i)
))
self.present(alert, animated: true, completion: nil)
return [delete]
搜索后删除项目的正确逻辑是什么?
【问题讨论】:
【参考方案1】:您必须在给定汽车的主数组中获取索引
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.destructive, handler: action in
let carToDelete = self.filteredCars.remove(at: indexPath.row)
self.cars.remove(at: self.cars.index(of: carToDelete)!)
tableView.deleteRows(at: [indexPath], with: .left)
这要求Car
采用Equatable
,这很容易实现。如果您将class
更改为struct
,您将免费获得Equatable
。
class Car : Equatable
var make = ""
var model = ""
static func == (lhs: Car, rhs: Car) -> Bool
return lhs.make == rhs.make && lhs.model == rhs.model
并始终使用作为参数传递的表格视图实例。
【讨论】:
在隐式提供 Equatable 的情况下,最好尽可能选择struct
而不是 class
。
顺便说一句,将默认值分配给属性作为不在场证明来编写初始化程序是不好的做法。
使用默认值,您永远无法声明常量 (let
),使用初始化程序 init(make: String, model:String)
,值也不能是 nil
。
静态函数==
确定两个对象是否相等。如果名称是唯一的,则这可以只是一个名称,或者如果make
和model
相同,则答案中两个对象相等。在您的特定情况下,有一个 UUID – 它是唯一的 – 因此,如果两个对象具有相同的 id
,则将它们视为相等就足够了,只需 return lhs.id == rhs.id
是的,但这是另一个懒惰的坏习惯。 Swift 的轻量值类型(struct)比 Objective-C 的重引用类型(NSObject 类)更高效。以上是关于使用 UISearchController 时如何删除排序/过滤的项目的主要内容,如果未能解决你的问题,请参考以下文章
如何在使用 popViewControllerAnimated(true) 导航出 UITableView 时修复 UISearchController 的警告
使用ios 8 UISearchController单击搜索栏时如何隐藏部分标题?
聚焦时如何调整 UISearchController.searchBar 的大小问题?
聚焦时如何修复 UISearchController 搜索栏调整大小?