Фильтр панели поиска не работает для моего элемента массива - PullRequest
0 голосов
/ 09 июля 2020

У меня есть несколько массивов, которые содержат заголовок, описание / примечания и дату выполнения. Таблица работает отлично, но теперь я добавляю ее в строку поиска. Однако фильтр ничего не улавливает, он не предлагает никаких всплывающих опций. Строка неисправности:

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

Это потому, что мне нужно вызвать элемент массива, а не только массив, например: run.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()
    }
}

1 Ответ

0 голосов
/ 09 июля 2020

В вашем коде есть некоторые проблемы:

viewWillAppear / viewDidLoad

Вы загружаете запуски обоими методами, что является избыточным. Вам не нужно делать это в viewDidLoad, потому что viewWillAppear будет вызываться сразу после viewDidLoad.

tableView (_: canEditRowAt:) Здесь, зачем вам снова сортировать прогоны? Удалите эту строку. Помните: каждый раз, когда вы меняете источник данных (добавляете, удаляете, меняете порядок), вам также необходимо обновить табличное представление

Фильтрация В вашем коде есть множество if searching ... операторов, которые сложно поддерживать, и вы уже можете видеть, что вам их не хватает в различных методах.

Лучше всего - как написал @ElTomato - иметь два отдельных массива, один из которых содержит «исходные» данные, а другой - «отфильтрованные».

  • В вашем коде вы почти всегда будете работать с отфильтрованными данными
  • при повторной загрузке, -фильтрации или отмене фильтра вы воссоздаете отфильтрованные данные из исходных данных. Если вы не фильтруете, они оба одинаковы
  • при изменении, вы изменяете исходные данные, а затем повторно создаете отфильтрованные данные
...