使用 UISearchController 时如何删除 sorted/filtered 项
How to delete sorted/filtered items when using UISearchController
以下代码成功创建,并在 UITableView
中显示 Cars
的列表,稍后您也可以在其中删除购物车。它还提供了一个 UISearchController
,您可以在其中成功执行搜索。
我的问题是尝试删除 search/filter 之后的汽车,例如,如果用户搜索位于数组中间的汽车,它将在table 的顶行,但如果 he/she 决定删除它,它将删除 cars
数组中的第一个项目,因为筛选的项目始终位于 [=18] 的顶部=]数组。在这里我没有得到任何错误,但它不会从 cars
数组中删除正确的项目,它总是从 cars
数组中删除第一个项目。
代码如下:
型号
class Car{
var make = ""
var model = ""
}
ViewController
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]
}
搜索后删除项目的正确逻辑是什么?
您必须获取给定汽车在主数组中的索引
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
}
}
并且始终使用作为参数传递的 table 视图实例。
以下代码成功创建,并在 UITableView
中显示 Cars
的列表,稍后您也可以在其中删除购物车。它还提供了一个 UISearchController
,您可以在其中成功执行搜索。
我的问题是尝试删除 search/filter 之后的汽车,例如,如果用户搜索位于数组中间的汽车,它将在table 的顶行,但如果 he/she 决定删除它,它将删除 cars
数组中的第一个项目,因为筛选的项目始终位于 [=18] 的顶部=]数组。在这里我没有得到任何错误,但它不会从 cars
数组中删除正确的项目,它总是从 cars
数组中删除第一个项目。
代码如下:
型号
class Car{
var make = ""
var model = ""
}
ViewController
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]
}
搜索后删除项目的正确逻辑是什么?
您必须获取给定汽车在主数组中的索引
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
}
}
并且始终使用作为参数传递的 table 视图实例。