由于可重复使用的单元格而导致UITableView混合值

时间:2015-10-29 15:39:24

标签: ios swift uitableview

当我在我的tableview中滚动时出现问题,其中包含可以水平滚动的元素,它混合了值。 enter image description here

enter image description here

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    var cell : RoundWorkoutCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! RoundWorkoutCell

    let tmpCell = cell

    print(tmpCell)

    if(cell == nil)
    {
        cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
    }
    let exerviseName = RoundLabels[indexPath.row]

    if(indexPath.row == 0){

        for countMe in 0..<self.round_1_exercises.count {
            if(countMe<1){
                roundPosition1.append(5)
            }else{
                roundPosition1.append(115+roundPosition1[countMe-1])
            }
            scrollerSize = 115+roundPosition1[countMe]
        }

    }else if(indexPath.row == 1){
        for countMe in 0..<self.round_2_exercises.count {
            if(countMe<1){
                roundPosition2.append(5)
            }else{
                roundPosition2.append(115+roundPosition2[countMe-1])
            }
            scrollerSize = 115+roundPosition2[countMe]
        }
    }else if(indexPath.row == 2){
        for countMe in 0..<self.round_3_exercises.count {
            if(countMe<1){
                roundPosition3.append(5)
            }else{
                roundPosition3.append(115+roundPosition3[countMe-1])
            }
            scrollerSize = 115+roundPosition3[countMe]
        }
    }......
    cell.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(scrollerSize),115)
    cell.RoundExercise_Cell_ScrollView.showsHorizontalScrollIndicator = true
    cell.RoundExercise_Cell_ScrollView.indicatorStyle = .Default


    if(indexPath.row==0){

        for index in 0..<self.round_1_exercises.count {
            print("Round position 1 \(self.roundPosition1[index])")

            var imageView : UIImageView
            imageView  = UIImageView(frame:CGRect(x:roundPosition1[index],y: 5, width:110, height: 110 ))
            imageView.backgroundColor = UIColor.whiteColor()
            cell.RoundExercise_Cell_ScrollView.addSubview(imageView)

            let label1: UILabel = UILabel()
            label1.frame = CGRect(x:roundPosition1[index],y: 5, width:110, height: 20 )
            label1.textColor = UIColor(red:17/255.0, green: 22/255.0, blue: 40/255.0, alpha:1.0)
            label1.textAlignment = NSTextAlignment.Center
            label1.font = UIFont(name: "OpenSans-CondensedLight", size: 14)
            label1.text = exerciseInfo.exercise_name(self.round_1_exercises[index] as! String)
            cell.RoundExercise_Cell_ScrollView.addSubview(label1)

            let frame1 = CGRect(x:roundPosition1[index]+10,y:25, width:90, height: 90 )
            let button = UIButton(frame: frame1)
            button.backgroundColor = UIColor.redColor()
            button.setBackgroundImage(UIImage(named: (self.round_1_exercises[index] as? String)!) as UIImage?, forState: .Normal)
            button.setTitleColor(UIColor.blackColor(), forState: .Normal)
            button.setTitle(self.round_1_exercises[index] as? String, forState: .Normal)
            button.setTitleColor(UIColor(red:0/255,green:0/255,blue:0/255,alpha:0.0), forState: .Normal)
            button.addTarget(self, action: "buttonClick:", forControlEvents: .TouchUpInside)
            cell.RoundExercise_Cell_ScrollView.addSubview(button)

            let label: UILabel = UILabel()
            label.frame = CGRect(x:roundPosition1[index],y: 115, width:110, height: 20 )
            label.font = UIFont(name: "OpenSans", size: 14)
            label.textColor = UIColor.whiteColor()
            label.textAlignment = NSTextAlignment.Center
            label.text = self.round_1_decoration[index] as? String
            cell.RoundExercise_Cell_ScrollView.addSubview(label)



        }
    }else if(indexPath.row == 1){
        for index in 0..<self.round_2_exercises.count {
             print("Round position 2 \(self.roundPosition2[index])")

            var imageView : UIImageView
            imageView  = UIImageView(frame:CGRect(x:roundPosition2[index],y: 5, width:110, height: 110 ))
            imageView.backgroundColor = UIColor.whiteColor()
            cell.RoundExercise_Cell_ScrollView.addSubview(imageView)

            let label1: UILabel = UILabel()
            label1.frame = CGRect(x:roundPosition2[index],y: 5, width:110, height: 20 )
            label1.textColor = UIColor(red:17/255.0, green: 22/255.0, blue: 40/255.0, alpha:1.0)
            label1.textAlignment = NSTextAlignment.Center
            label1.font = UIFont(name: "OpenSans-CondensedLight", size: 14)
            label1.text = exerciseInfo.exercise_name(self.round_2_exercises[index] as! String)
            cell.RoundExercise_Cell_ScrollView.addSubview(label1)

            let frame1 = CGRect(x:roundPosition2[index]+10,y:25, width:90, height: 90 )
            let button = UIButton(frame: frame1)
            button.backgroundColor = UIColor.redColor()
            button.setBackgroundImage(UIImage(named: (self.round_2_exercises[index] as? String)!) as UIImage?, forState: .Normal)
            button.setTitleColor(UIColor.blackColor(), forState: .Normal)
            button.setTitle(self.round_2_exercises[index] as? String, forState: .Normal)
            button.setTitleColor(UIColor(red:0/255,green:0/255,blue:0/255,alpha:0.0), forState: .Normal)
            button.addTarget(self, action: "buttonClick:", forControlEvents: .TouchUpInside)
            cell.RoundExercise_Cell_ScrollView.addSubview(button)

            let label: UILabel = UILabel()
            label.frame = CGRect(x:roundPosition2[index],y: 115, width:110, height: 20 )
            label.font = UIFont(name: "OpenSans", size: 14)
            label.textColor = UIColor.whiteColor()
            label.textAlignment = NSTextAlignment.Center
            label.text = self.round_2_decoration[index] as? String
            cell.RoundExercise_Cell_ScrollView.addSubview(label)



        }
    }.....
    cell.RoundExercise_Cell_Label.text = exerviseName

    return cell as RoundWorkoutCell
}

这是自定义单元格类

class RoundWorkoutCell: UITableViewCell {

@IBOutlet var RoundExercise_Cell_Label: UILabel!
@IBOutlet var RoundExercise_Cell_ScrollView: UIScrollView!


override func awakeFromNib() {
    super.awakeFromNib()

    // Initialization code
    self.RoundExercise_Cell_Label.text = ""
    self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
}

我之前已经放置了这个帖子,但是没有人回答。我需要解决这个问题。我已经完成了我的整个应用程序而且还剩下了。我知道我必须以某种方式使用prepareForReuse()但我不确定如何,或者是否我可以禁用这个可重复使用的细胞。 感谢

4 个答案:

答案 0 :(得分:2)

The cells are reused to save on memory, this means that you need to recycle them properly to stop old data from being shown. You can do this by adding the prepareForReuse() function into your tableviewCell. In here you will need to set image outlets to be empty i.e by setting it to UIImage(). You will need to do the same with all outlets. This will ensure that old data that is not relevant will not be shown.

Example:

override func prepareForReuse() {
    //myOutletName = myNilValue 
    super.prepareForReuse()
}

答案 1 :(得分:1)

If you don't want to reuse cells, you can simply remove the call to dequeueReusableCellWithIdentifier. Try replacing these lines:

var cell : RoundWorkoutCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! RoundWorkoutCell

let tmpCell = cell

print(tmpCell)

if(cell == nil)
{
    cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
}

With this:

cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;

This approach doesn't reuse cells and will be less performant and will leak memory.


A better approach would be to construct the cells once and then reuse them, instead of rebuilding them in cellForRowAtIndexPath method. For example, if you design the cells in the NIB (as you are doing now), there's no need to add buttons and labels again by code, you can simply change the contents and hide those that are not needed.

Then, on prepareForReuse (or even at the beginning of cellForRowAtIndexPath), you reset the content of the row to the initial state.

答案 2 :(得分:1)

类RoundWorkoutCell:UITableViewCell {

@IBOutlet var RoundExercise_Cell_Label: UILabel!
@IBOutlet var RoundExercise_Cell_ScrollView: UIScrollView!





override func awakeFromNib() {
    super.awakeFromNib()

    // Initialization code
    self.RoundExercise_Cell_Label.text = ""
    self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
}

override func prepareForReuse() {
    //myOutletName = myNilValue

    self.RoundExercise_Cell_Label.text = ""
    self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)

    for subview in RoundExercise_Cell_ScrollView.subviews {
            print(subview)
            subview.removeFromSuperview()
    }

    super.prepareForReuse()
}

}

答案 3 :(得分:1)

@ Swinny89是对的,谢谢你,但我可以添加更多关于prepareForReuse方法的细节。如果在该方法中删除所有重用的单元格数据,性能将降低。另一方面,您可以在prepareForReuse方法中隐藏变量,并在单元初始化方法中使它们可见。

例如我的方式:

override func prepareForReuse() {

    if(commentLabels != nil) {
        for item in commentLabels {
            item.hidden = true
        }
    }

    super.prepareForReuse()
}

在其他方法中,如果检查,我可以看到:

    if(commentLabels == nil) {
        // creating new labels and adding to commentLabels

    } else { // it means reuse cell data and it has been hidden
        // hidden = false
        for item in commentLabels {
            item.hidden = false
        }

    }