【问题标题】:Search bar filter not working for my array item搜索栏过滤器不适用于我的数组项
【发布时间】:2020-07-09 01:15:21
【问题描述】:

我有一些数组,其中包含标题、描述/注释和运行日期。该表运行良好,但现在我在搜索栏中添加。但是,过滤器没有拾取任何东西,它不提供任何弹出选项。问题线:

searchingRuns = runs.filter({$0.title.lowercased().prefix(searchText.count) == searchText.lowercased()})

这是因为我需要调用数组项而不仅仅是数组,例如:runs.title.filter ...我确实尝试过,但没有成功。

import UIKit

class RunTableViewController: UITableViewController, RunCellDelegate, UISearchBarDelegate {
    
    var runs = [Run]()
    
    @IBOutlet weak var searchBar: UISearchBar!
    
    var searchingRuns = [String]()
    var searching = false
    
    override func viewWillAppear(_ animated: Bool) {
        if let savedRuns = Run.loadRuns() {
            runs = savedRuns
        }
        
        runs.sort { $0.runDate > $1.runDate}
        tableView.reloadData()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationItem.leftBarButtonItem = editButtonItem
        
        if let savedRuns = Run.loadRuns() {
            runs = savedRuns
        }
        
        runs.sort { $0.runDate > $1.runDate}
        tableView.reloadData()
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if searching {
            return searchingRuns.count
        } else {
        return runs.count
        }
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "RunCellIdentifier") as? RunCell else {
            fatalError("Could not dequeue a cell")
        }
        if searching {
            cell.textLabel?.text = searchingRuns[indexPath.row]
        } else {
        
        cell.delegate = self
        
        let run = runs[indexPath.row]
        cell.titleLabel?.text = run.title
        cell.descriptionLabel.text = run.notes
        cell.dateLabel.text = Run.runDateFormatter.string(from: run.runDate)
        }
       
        return cell
    }
    
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        
        runs.sort { $0.runDate > $1.runDate}
        
        return true
    }
    
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            runs.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
            Run.saveRuns(runs)
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetails" {
            let runViewController = segue.destination as! RunViewController
            let indexPath = tableView.indexPathForSelectedRow!
            let selectedRun = runs[indexPath.row]
            runViewController.run = selectedRun
        }
    }
    
    @IBAction func unwindToRunList(segue: UIStoryboardSegue) {
        guard segue.identifier == "saveUnwind" else { return }
        let sourceViewController = segue.source as! RunViewController
        
        if let run = sourceViewController.run {
            if let selectedIndexPath = tableView.indexPathForSelectedRow {
                runs[selectedIndexPath.row] = run
                tableView.reloadRows(at: [selectedIndexPath], with: .none)
            } else {
                let newIndexPath = IndexPath(row: runs.count, section: 0)
                runs.append(run)
                tableView.insertRows(at: [newIndexPath], with: .automatic)
            }
        }
        
        Run.saveRuns(runs)
        
        if let savedRuns = Run.loadRuns() {
            runs = savedRuns
        }
       
        runs.sort { $0.runDate > $1.runDate}
        tableView.reloadData()
    }
    
    func checkmarkTapped(sender: RunCell) {
        if let indexPath = tableView.indexPath(for: sender) {
            let run = runs[indexPath.row]
            runs[indexPath.row] = run
            tableView.reloadRows(at: [indexPath], with: .automatic)
            Run.saveRuns(runs)
        }
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchingRuns = runs.filter({$0.title.lowercased().prefix(searchText.count) == searchText.lowercased()})
        searching = true
        tableView.reloadData()
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searching = false
        searchBar.text = ""
        tableView.reloadData()
    }
}

【问题讨论】:

  • 取消的最后一部分是错误的,因为您没有更改字符串数组。所以没有必要重新加载表。你需要的是两个字符串数组。一个数组包含所有字符串。所以当搜索字段不包含关键字时返回这个字符串数组。并使用另一个数组过滤第一个数组。

标签: arrays swift xcode uisearchbar


【解决方案1】:

您的代码中存在一些问题:

viewWillAppear/viewDidLoad

您正在以两种方法加载运行,这是多余的。 您不需要在 viewDidLoad 中执行此操作,因为 viewWillAppear 将在 viewDidLoad 之后被调用。

tableView(_:canEditRowAt:) 在这里,您为什么要再次对运行进行排序?删除该行。 请记住:任何时候更改数据源(添加、删除、更改顺序),都需要更新表格视图

过滤
您的代码中有一堆if searching ... 语句,很难维护,您已经可以看到您在各种方法中都缺少它。

最好的办法是——就像@ElTomato 写的那样——拥有两个独立的数组,一个保存“原始”数据,一个保存“过滤”数据。

  • 在您的代码中,您几乎总是会使用过滤后的数据
  • 在重新加载、过滤或取消过滤器时,您会根据原始数据重新创建过滤后的数据。如果你不过滤,它们都是一样的
  • 修改时,修改原始数据,然后重新创建过滤后的数据

【讨论】:

    猜你喜欢
    • 2020-07-17
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    相关资源
    最近更新 更多