Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
203 views
in Technique[技术] by (71.8m points)

ios - UITableView Checkmarks at the wrong place after search

I want to search in my tableView, set checkmarks and save the objects with the checkmarks in Realm. But if I set a checkmark after a search and cancel the search, the checkmark is at the indexPath that I clicked on, and not at the object. I can't explain it better, so here's an example: After I search an exercise.

After I clicked the cancel button

Here's my code:

class ShowExcercisesTableViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

//Properties
let realm = try! Realm()
var request2: Results<Excercise>?{
    didSet{
        tableView.reloadData()
    }
}
var searchOrNot: Excercise?
var searchResults = try! Realm().objects(Excercise.self)
var resultSearchController: UISearchController!
var shouldShowSearchResults = false
var muscleGroupForSearch: String?

//Searchbar Funktionen
func filterResultsWithSearchString(searchString: String){
    let predicate = NSPredicate(format: "name CONTAINS [c]%@ AND muscleGroup =%@ AND copied = false", searchString, muscleGroupForSearch!)
    searchResults = realm.objects(Excercise.self).filter(predicate).sorted(byProperty: "name", ascending: true)
}

func updateSearchResults(for searchController: UISearchController) {
    let searchString = searchController.searchBar.text
    filterResultsWithSearchString(searchString: searchString!)
    tableView.reloadData()
}

func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
    shouldShowSearchResults = true
    tableView.reloadData()
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    shouldShowSearchResults = false
    tableView.reloadData()
}

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    if !shouldShowSearchResults {
        shouldShowSearchResults = true
        tableView.reloadData()
    }
    resultSearchController.searchBar.resignFirstResponder()
}

//Lifecycle
override func viewDidLoad() {
    super.viewDidLoad()

    self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.searchBar.delegate = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()
        controller.searchBar.placeholder = "Suche übungen..."

        self.tableView.tableHeaderView = controller.searchBar

        return controller
    })()

    self.tableView.reloadData()
}

//TableView Funktionen
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if shouldShowSearchResults {
        return searchResults.count
    }
    else{
        return request2!.count
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: ShowExcercisesTableViewCell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier.showExcercises, for: indexPath) as! ShowExcercisesTableViewCell
    if shouldShowSearchResults{
        let excercise = searchResults[indexPath.row]
        cell.nameLabel.text = excercise.name
        if fromTrainingPlan{
        if excercise.selected == true{
            cell.accessoryType = .checkmark
        }
        else{
            cell.accessoryType = .none
        }
        }
        return cell
    }
    else{
        let excercise = request2![indexPath.row]
        cell.nameLabel.text = excercise.name
        if fromTrainingPlan{
        if excercise.selected == true{
            cell.accessoryType = .checkmark
            }
        else{
            cell.accessoryType = .none
        }
        }
        return cell
    }
}

//Checkmarks
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if fromTrainingPlan == true && request2 != nil{
        if shouldShowSearchResults{
            searchOrNot = searchResults[indexPath.row]
        }
        else{
            searchOrNot = request2![indexPath.row]
        }
        tableView.deselectRow(at: indexPath, animated: true)

        let cell: ShowExcercisesTableViewCell = tableView.cellForRow(at: indexPath) as! ShowExcercisesTableViewCell
        do {
            try realm.write {
                searchOrNot!.selected = !searchOrNot!.selected
            }
        }
        catch{
            print(error)
        }

        if searchOrNot!.selected {
            cell.accessoryType = .checkmark
        }
        else {
            cell.accessoryType = .none
        }
    }
}

Sorry for so much code, I'm not sure what is relevant and what not. Is there any way to set the checkmarks at the right places after the search? Thanks in advance!

It's working now.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In your cellForRowAtIndexPath, you need to disable the checkmark for cells that do not need it. You are only enabling for cells that do.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: ShowExcercisesTableViewCell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier.showExcercises, for: indexPath) as! ShowExcercisesTableViewCell
    if shouldShowSearchResults{
        let excercise = searchResults[indexPath.row]
        cell.nameLabel.text = excercise.name
        if excercise.selected == true{
            cell.accessoryType = .checkmark
        } else {
            cell.accessoryType = .none // Add this code here
        }
        return cell
    }
    else{
        let excercise = request2![indexPath.row]
        cell.nameLabel.text = excercise.name
        if excercise.selected == true {
            cell.accessoryType = .checkmark
        } else {
            cell.accessoryType = .none // Add this code here
        }
        return cell
    }
}

UITableViews reuse the cells internally. So when you are searching, you are saying cell one has a checkmark, then when you cancel, it goes back to the table and looks at the cells and your cellForRow code never tells it that cell one is no longer checked, thus it maintains the checkmark there. The cell is not being recreated, its already exists, so you cannot make an assumption about what state it is in (not checked or checked).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...