UITableView Checkmarks 在错误的地方搜索后

Posted

技术标签:

【中文标题】UITableView Checkmarks 在错误的地方搜索后【英文标题】:UITableView Checkmarks at the wrong place after search 【发布时间】:2017-02-05 19:14:19 【问题描述】:

我想在我的 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
        
    

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

现在可以了。

【问题讨论】:

cell.accessoryType = selectedCells.contains(indexPath) ? .Checkmark : .NonecellForRowAt 尝试将代码放在您在willDisplayCell中设置复选标记的位置 我也用willDisplayCell试过了,结果一样 @NazmulHasan,我不明白你的意思,对不起,我是 Swift 的新手 .selectedfromTrainingPlan 是什么? 【参考方案1】:

在您的cellForRowAtIndexPath 中,您需要禁用不需要它的单元格的复选标记。您只启用了这样做的单元格。

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 代码永远不会告诉它不再检查单元格一,因此它保持复选标记那里。单元格没有被重新创建,它已经存在,所以你不能假设它处于什么状态(未检查或检查)。

【讨论】:

你对我的回答投了反对票,并告诉我我错了,代码 cellForRowAtIndexPath 不知道应该标记哪个单元格,你基本上重复了完全相同的事情。我明确地说 cellForRowAtIndexPath 不知道应该标记哪个单元格,您重复了我的回答。恭喜你复制了我的答案。如果他想在 cellForRowAtIndexPath 中放置多个选项,或者更确切地说是多个单元格,会发生什么情况?那么您复制的“答案”中的“If / Else”语句将完全失败并选中/取消选中所有单元格。 @Sneak Ummmm,我的答案绝不是你的副本。你在我的发布后编辑了你的。您发布的是“您需要保存对索引路径的引用”的 3 行文本。如果您认为我在攻击您或其他什么,我深表歉意,但您的回答是错误的。如果您更正它,我将删除我的反对票。 "你在我的发布后编辑了你的。" , uummmmmmm 是的,我编辑了它并添加了 Apple 文档供您阅读,也许您看不到 EDIT 标记? 我尝试了您的解决方案,但不幸的是它不起作用。行为发生了一些变化。现在,如果我在开始搜索之前选择 tableView 中的对象,然后使用搜索,则正确的对象将保持选中状态。但是,如果我在使用搜索栏后从 searchResults 数组中选择对象,然后使用搜索栏的取消按钮,以便再次显示 request2 数组,则选择了错误的对象。也许还有其他想法?顺便说一句:对不起我的英语不好 现在可以使用了!我只在 didSelectRow 函数中做了一点改动。我编辑了我的问题。【参考方案2】:

复选标记位于我单击的 indexPath 处

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

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

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

编辑:

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

可重复使用的细胞

prepareForReuse

如果 UITableViewCell 对象是可重用的——也就是说,它具有重用性 标识符——这个方法在对象返回之前被调用 从 UITableView 方法 dequeueReusableCellWithIdentifier:.为了 性能原因,您应该只重置单元格的属性 与内容无关,例如 alpha、编辑和选择 状态tableView:cellForRowAtIndexPath 中的 table view 的委托: 重用单元格时应始终重置所有内容。如果细胞 对象没有关联的重用标识符,此方法是 不叫。如果你重写这个方法,你必须确保调用 超类实现。

【讨论】:

投反对票,因为这是不正确的。他正在检查是否选择了某些东西并根据它确定复选标记。他不需要以任何方式保存索引路径。 当然,你的答案是我的完美副本。如果他想在 cellForRowAtIndexPath 中放置多个选项,或者更确切地说是多个单元格,会发生什么?那么您复制的“答案”中的“If / Else”语句将完全失败并选中/取消选中所有单元格。 您对you need to keep a reference to what indexPath is supposed to be selected 的回答是错误的。对不起。 @ColdLogic 也许我的英语不太好,但让我们再试一次:“如果他想在 cellForRowAtIndexPath 中放置多个选项,或者更确切地说是多个单元格,会发生什么?” 或者 Apple 文档是错误的,但你是对的。 如果他要使用多个单元格,那么他将使用他的解决方案来检查数据并据此确定复选标记。如果他要保存对 indexPath 的引用,他将没有数据和 indexPath 之间的链接,因此会遇到同样的问题。没有我在哪里说“苹果文档是错误的”。我说你解决问题的方法是错误的。如果您想加入聊天,我将非常乐意帮助您解决问题。

以上是关于UITableView Checkmarks 在错误的地方搜索后的主要内容,如果未能解决你的问题,请参考以下文章

线程池,千万注意,原来很多人都在错用

用appium测试的时候遇到这个报错,有没有大佬帮忙看看

《少林问道》

Titan 检索顶点属性

UITableViewCell 删除然后所有复选标记在swift上消失

深入了解MVC(转)