搜索后,UITableView选中标记位置错误

时间:2017-02-05 19:14:19

标签: ios swift uitableview uisearchbar nsindexpath

我想在我的tableView中搜索,设置复选标记并使用Realm中的复选标记保存对象。但是如果我在搜索后设置了一个复选标记并取消搜索,则复选标记位于我单击的indexPath处,而不是该对象。我不能更好地解释它,所以这是一个例子: After I search an exercise.

After I clicked the cancel button

这是我的代码:

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
        }
    }
}

很抱歉这么多代码,我不确定什么是相关的,什么不是。有没有办法在搜索后在正确的位置设置复选标记?提前谢谢!

现在正在运作。

2 个答案:

答案 0 :(得分:0)

  

复选标记位于我点击的indexPath

您没有告诉代码您要复选标记的indexPath。当您的单元格被重用时:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

您需要保留对应该选择indexPath的引用并显示checkMark,以便在内部重用单元格时,单元格在正确的indexPath上显示checkMark。

修改

似乎有些人在没有阅读框架的工作原理和阅读Apples Documentation.

的情况下将自己的答案视为自己的答案并将其修改为自己的答案

可重复使用的细胞

prepareForReuse
  

如果UITableViewCell对象可重用 - 也就是说,它具有重用性   标识符 - 在返回对象之前调用此方法   来自UITableView方法dequeueReusableCellWithIdentifier:。对于   性能原因,你应该只重置单元格的属性   与内容无关,例如,alpha,编辑和选择   状态即可。表视图在 tableView:cellForRowAtIndexPath中的委托:   重复使用单元格时应始终重置所有内容。如果是细胞   对象没有关联的重用标识符,此方法是   不叫。如果重写此方法,则必须确保调用   超类实现。

答案 1 :(得分:0)

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

cell one has a checkmark在内部重用单元格。因此,在您搜索时,您正在说cellForRow,然后当您取消时,它会返回到表中并查看单元格,而您的{{1}}代码永远不会告诉它不再检查单元格1,因此它保持那里的复选标记。单元格没有被重新创建,它已经存在,所以你不能假设它处于什么状态(未经检查或检查)。