使用reloaddata时,UITableViewCell未从UITableView中删除

时间:2016-02-22 16:10:42

标签: ios swift uitableview

我正在使用tableview在左侧菜单中显示某些类别。当您选择它时,单元格中的数据将更改为该类别中的课程('Cursussen')。

每个单元格都包含UIImageViewUILabel

我刚才注意到,当您在左侧菜单中选择课程时,标签将更改为某个类别的标签。当时这不是一个大问题,但现在我正在努力禁用某些课程,如果它们不可用,它突然变成了一个大问题。为了表明一个不可用的课程,我设置了label.enabled = false,它工作正常,但是我还需要阻止用户点击它并导航到一个不可用的课程。为此,我正在使用tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)检查UILabel是否已启用。如果它被禁用,应用程序将无法导航到课程。

回到这个问题,点击不可用的课程(显示正确的图像和标签)将触发didSelectRowAtIndexPath委托,但是当我将Cell出列并检查{是否{ {1}}中的{1}}被禁用,因此恰好启用而且UILabel不等于我在应用中看到的值。

选择行前的状态: unselected

选择行后的状态: selected

cellForRowAtIndexPath方法:

label.text

didSelectRowAtIndexPath方法:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
    -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("LeftCell", forIndexPath: indexPath)
        let label = cell.contentView.subviews[0] as! UILabel
        let image = cell.contentView.subviews[1] as! UIImageView
        if(selectedCategory.ID > 0 || searchCursusses.count > 0) {
            //Category is selected, load course into cell
            var cursus : Cursus
            if(selectedCategory.ID > 0) {
                cursus = cursusses[indexPath.row] as Cursus
            } else {
                cursus = searchCursusses[indexPath.row] as Cursus
            }
            image.image = self.chooseImage(false, name: cursus.category!.Name)
            label.numberOfLines = 0
            label.text = cursus.name
            label.lineBreakMode = .ByTruncatingTail
            if(defaults.boolForKey("offline-mode")) {
                let realm = try! Realm()
                let videos = realm.objects(DownloadedVideo).filter("video.cursus.ID = %@", cursus.ID)
                if(videos.count > 0) {
                    label.enabled = true
                } else {
                    label.enabled = false
                }
            } else {
                label.textColor = UIColor.blackColor()
            }
            cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
            cell.setSelected(false, animated: false)
        } else {
            let category = categories[indexPath.row] as Category
            image.image = self.chooseImage(false, name: category.Name)
            label.numberOfLines = 0
            label.text = category.Name
            label.lineBreakMode = .ByTruncatingTail
            label.textColor = UIColor.blackColor()
            cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        }
        return cell
}

调用func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let cell = tableView.dequeueReusableCellWithIdentifier( "LeftCell", forIndexPath: indexPath) cell.selectionStyle = .None if(selectedCategory.ID > 0 || searchCursusses.count > 0) { let label = cell.contentView.subviews[0] as! UILabel if(!label.enabled) { return } let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil) let resultViewController = storyBoard.instantiateViewControllerWithIdentifier("CursusView") as! CursusViewController if(selectedCategory.ID > 0) { resultViewController.loadCursus(self.cursusses[indexPath.row], completionHandler: { self.presentViewController(resultViewController, animated:true, completion:nil) }) } else { resultViewController.loadCursus(self.searchCursusses[indexPath.row], completionHandler: { self.presentViewController(resultViewController, animated:true, completion:nil) }) } } else { let category = categories[indexPath.row] as Category cell.setSelected(true, animated: false) let label = cell.contentView.subviews[0] as! UILabel let image = cell.contentView.subviews[1] as! UIImageView if(label.textColor == UIColor.lightGrayColor()) { return } else { image.image = self.chooseImage(true, name: category.Name) label.numberOfLines = 0 label.text = category.Name label.textColor = UIColor.whiteColor() label.lineBreakMode = .ByTruncatingTail cell.backgroundColor = UIColor(red: 45.0/255.0, green: 145.0/255.0, blue: 220.0/255.0, alpha: 1.0) self.selectedCategory = category self.topBarTitle.text = category.Name let realm = try! Realm() let cursusses = realm.objects(Cursus).filter("category.ID = %@", selectedCategory.ID) for cursus in cursusses { self.cursusses.append(cursus) } let title = self.leftMenuNav.subviews[0] as! UILabel let titleImg = self.leftMenuNav.subviews[1] as! UIImageView titleImg.image = UIImage(named: "back-icon") title.text = "Cursussen" dispatch_async(dispatch_get_main_queue(), { () -> Void in self.tableView.slideInFromRight(0.5) self.tableView.reloadData() self.collectionView.crossFade(0.3) self.collectionView.reloadData() }) } } } 后似乎没有正确清理旧单元格,导致多个单元格位于同一个IndexPath。

我在这里不知所措,请帮助!

3 个答案:

答案 0 :(得分:1)

问题在于

let cell = tableView.dequeueReusableCellWithIdentifier( "LeftCell", forIndexPath: indexPath)
<{1>}函数中的

,因为它正在创建一个新单元(或尝试重用一个单元)并破坏表视图单元缓存。

您应该使用didSelectRowAtIndexPath函数来获取现有单元格。

答案 1 :(得分:1)

您的方法存在问题:didSelectRowAtIndexPath应该查看模型中的数据,而不是视图中的数据。您的代码正在尝试错误地访问cell并检查其标签等。相反,您的方法应该访问用于制作标签的相同底层数据源。

换句话说,而不是写

let label = cell.contentView.subviews[0] as! UILabel

然后检查标签的启用/禁用状态

你应该写

cursus = cursusses[indexPath.row] as Cursus

并检查cursus的可用性。

一个经验法则是,当您看到代码访问UITableViewCell cellForRowAtIndexPath之外的组件时,您应该非常怀疑。测试标签的状态几乎普遍表明代码不正确。

答案 2 :(得分:1)

你做错了。只有tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell才能使单元格出列并设置其内容。

为了防止选择,您应该对func tableView(_ tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath做出反应并返回nil,表示您不想选择任何内容。

主要问题是您正在编写复杂的方法。很难弄清楚你在做什么,你的意图是什么。 (will/did)SelectRowAtIndexPath应该只调用一个/拖动一些简单的方法,例如:执行segue或加载一些数据。