11

I am using a UITableView and I'm noticing that the cells in my tableview are getting progresively bolder as I scroll, it is overwriting the contents and I want to stop this but can't see where I'm going wrong.

On my UITableView, for some reason when I scroll the contents of the tableview get messed up with the the manually created UILabel.

I require a manual UILabel because I need to have custom cells later on.

As I scroll up and down, the labels get progressively bolder and bolder; they always overlap and sometimes even affects rows lower down (even before they are in the viewport).

If I keep doing it, the cell contents become unintelligable.

This only happens if there the backgroundColor is not set as clearColor.

I have attempted [cellLabel setClearsContextBeforeDrawing:YES]; and [self.tableView setClearsContextBeforeDrawing:YES]; to no effect.

If I use cell.textLabel.text then the problem seems to go away.

Code and an image sample follows.

  // Simple table view
    - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        }

        // Configure the cell...
        //[self configureCell:cell atIndexPath:indexPath];


        NSString *txt = @"Product";


        //cell.textLabel.text = txt;
        cell.selectionStyle = UITableViewCellSelectionStyleNone;

        UIView *cellView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, cell.frame.size.height)];

        UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
        [cellLabel setText:txt];
        [cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
        [cellLabel setBackgroundColor:[UIColor clearColor]];

        [cellView addSubview:cellLabel];
        [cellLabel release];
        [cell.contentView addSubview:cellView];
        [cellView release];


        return cell;
    }


Image follows;


![image of uitableview][1]


  [1]: https://i.stack.imgur.com/5lNy6.png


// Edit to include context

I am using a dictionary to display the contents of the UITableViewCells.

I have attempted to do the following;

    - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

            [self configureCell:cell atIndexPath:indexPath];
        } // end if


        // Configure the cell...
        //
       // Moved to inside the cell==nil        

        return cell;
    }

-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{

    // Get the txt from the Dictionary/Plist... *removed due verboseness*

    UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
    [cellLabel setText:txt];
    [cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
    [cellLabel setBackgroundColor:[UIColor clearColor]];

    [cell.contentView addSubview:cellLabel];
    [cellLabel release];
}

This, although it fixes the problem of overwriting -- it causes a problem -- it makes labels repeatedly appear in totally random places -- the following is just an example, other fields and labels also repeat.

See picture below;

repeating labels in uitableview

IPS Brar
  • 346
  • 1
  • 14
zardon
  • 2,910
  • 6
  • 37
  • 58
  • possible duplicate of [UITableView repeating cells on scroll](http://stackoverflow.com/questions/6844156/uitableview-repeating-cells-on-scroll) – jscs Mar 20 '12 at 22:15

7 Answers7

17
    // cell reuse
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

returned you the cell already been used, it already has an UILabel subview and you are adding another over it. Put the adding subviews at the section

   if (cell == nil) { //cell initialization

and edit the subviews as needed after the cell initialization, you can access them by tag for example.

A-Live
  • 8,904
  • 2
  • 39
  • 74
  • I've tried setting up the UILabels underneath the `cell == nil` part, whilst this does stop the overwriting, it causes another problem -- it puts data in random areas in the tableview. My actual full code uses a dictionary (plist), and the cell starts putting the same entry in random places throughout the table, I will update my question to cover this issue. – zardon Mar 20 '12 at 21:23
  • 2
    @zardon the UILabels being added once is not cleared when you reuse the cell with `dequeueReusableCellWithIdentifier`, that's your responsibility to update the subviews content or to reset it's appearance to default (like setText:@"" for UILabel). Otherwise previously configured subviews will be possibly displayed at reused cells (in case you are changing the cell content conditionally). – A-Live Mar 20 '12 at 21:31
  • I tried updating the context, but I Don't think its working. I'll try making the UILabels init inside the cell==nil and try to access them by tag and see if that helps. I might look for tutorials on this too as I've never seen this approach before. – zardon Mar 20 '12 at 21:35
  • @zardon you can find one here: http://kwigbo.com/post/3183498279/custom-uitableviewcell-without-subclassing (simple) or here: http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html (more complex, and I like it very much). As you might guess, another approach is to subclass the `UITableViewCell`, but that makes code different as you are adding subviews at you custom Cell class, not at `cellForRowAtIndexPath` delegate method. Tutorial: http://zcentric.com/2008/08/05/custom-uitableviewcell/ (sorry, just the first one w/o fancy code formatting, google to find more). – A-Live Mar 20 '12 at 21:44
  • Thanks A-Live. iOS Recipes book seems to give a basic overview too -- I will use your ideas and report back. It might be a while as I need to test a few scenarios, but if successful I will accept and up-vote your answer. Thanks – zardon Mar 21 '12 at 06:51
  • I found https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html to be very helpful! It gives a broader example of what A-Live means. I have been able to solve the issue of overwriting cells and have added my solution, however this answer has been accepted. – zardon Mar 21 '12 at 08:19
6

You are adding the label to the same reused cell every time, that is why it is getting bolder. When you use dequeueReusableCellWithIdentifier, you are grabbing a cell that has already been displayed on the screen, which is the correct thing to do, but you have already put a label on it. As the label will be in the same position relative to the cell each time, and the same color etc.. (the only dynamic element will be the text), you should set all this up only once.

My preferred solution is to create a custom cell with the properties that you want. So in this case, you would create

@interfacce MyCustomCell : UITableViewCell
    @property (nonatomic) UILabel *cellLabel;
@end

Give it a property UILabel *cellLabel, and do all the code you have above apart from setting the labels text in the init of MyCustomCell.m, replace any instances of cell with self, for example:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self)
    {
        self.cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
        [self.cellLabel setText:txt];
        [self.cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
        [self.cellLabel setBackgroundColor:[UIColor clearColor]];
    }

    return self;
}

Now in your cellForRowAtIndexPath use MyCustomCell, where you check if cell == nil, you might want to also check the cell label:

if(cell == nil || cell.cellLabel == nil)

Initialise it in exactly the same way:

cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

now, all you need to do is set:

cell.cellLabel.text = ....;

your code in cellForRowAtIndexPath is a lot cleaner, memory efficient and and you will not get your bug.

Remember to set your cell to be of type MyCustomCell in interface builder.

felbus
  • 2,639
  • 2
  • 24
  • 30
4
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 

           UITableViewCell *cell = (UITableViewCell*)[self.YourTableName dequeueReusableCellWithIdentifier:nil];        
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
        }


            return cell; 
        }

use ReusablecellIdentifier nil so it working correctly.....

jayesh kavathiya
  • 3,531
  • 2
  • 22
  • 25
  • i had tried xcode 7 ReusablecellIdentifier nil is not working. its show some null passed cellsee non argument warning issue. – Mohan.C Nov 02 '15 at 14:51
4

This is a bit older thread. But will be useful to someone,

You can remove any view added to a cell before the same being reused in the tableView.

This code will do that,

for (UIView* view in [cell.contentView subviews])
{
    if ([view isKindOfClass:[UILabel class]])  //Condition if that view belongs to any specific class       
    {
        [view removeFromSuperview];
    }
}

This can be added before configuring the cell,

if (!cell) {
    cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier];

} 

You can also make cell's label values to nil to avoid repetition in trailing cells.

cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
cell.textLabel.font = nil;
Ram Gandhi
  • 707
  • 8
  • 24
2

Write this code for collectionView. It will help to remove duplicity from reusable cell.

- (void)viewDidLoad {
[super viewDidLoad];
arrImg=[[NSMutableArray alloc]initWithObjects:@"images.jpeg",@"images-2.jpeg",@"images-3.jpeg", nil];

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(375, 200)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];

[self.colView setCollectionViewLayout:flowLayout];
self.colView.backgroundColor=[UIColor lightGrayColor];
self.colView.delegate=self;
self.colView.dataSource=self;

// Do any additional setup after loading the view, typically from a nib.
 }

  -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {


CollectionViewCell1 *cell=(CollectionViewCell1 *)[colView dequeueReusableCellWithReuseIdentifier:@"CollectionViewCell1" forIndexPath:indexPath];
float xAxis=0;
float maxwidth=0;


for (UIView* view in [cell.contentView subviews])
{
    if ([view isKindOfClass:[UIScrollView class]])  //Condition if that view belongs to any specific class
    {
        [view removeFromSuperview];
    }
}
if(indexPath.row==1)
{
    UIScrollView *scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(0,0, colView.frame.size.width, 200)];

    scroll.delegate = self;
    [cell.contentView addSubview:scroll];

    for(int i=0;i<[arrImg count];i++)
    {

    UIImageView *img=[[UIImageView alloc]init];
    xAxis=xAxis+maxwidth;
    img.frame=CGRectMake(xAxis, 0, self.view.frame.size.width, 200);
    img.image=[UIImage imageNamed:[NSString stringWithFormat:@"%@",[arrImg objectAtIndex:i]]];
        [scroll addSubview:img];
        maxwidth=self.view.frame.size.width;
    }

   scroll.contentSize=CGSizeMake(375*3, 200);
   scroll.pagingEnabled=YES;


}
   return cell;

}
Anuj Kumar Rai
  • 666
  • 1
  • 6
  • 17
0

Try to not put the UIView *cellView over the UITableViewCell *cell. The UITableViewCell is a subclass of an UIView so you can add subviews if you want. However UITableViewCell has already a label inside.

Just use [cell.textLabel setText:txt].

Lolloz89
  • 2,809
  • 2
  • 26
  • 41
  • I can't use textLabel for this task because i need to combine a textlabel, an input gadget as well as other gadgets too. – zardon Mar 20 '12 at 21:18
-1

A-Live's answer was the best solution.

I found https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html to give a much broader example.

However, in my experiments I was able to set up UITableViewCells that did not overwrite, and did not put cell values in random positions.

The code I used is below, it could do with tiyding up, but it seems to work for now;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
    [cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
    [cellLabel setBackgroundColor:[UIColor clearColor]];
    [cellLabel setTag:1];
    [cell.contentView addSubview:cellLabel];
    [cellLabel release];




    // TextInput setup    
    CGRect cellTextFrame = CGRectMake(200, 12, 65, 30);


    UITextField *txtInputField = [[UITextField alloc] initWithFrame:cellTextFrame];
    [txtInputField setTag:2];
    [txtInputField setDelegate:self];
    [txtInputField setClearButtonMode:UITextFieldViewModeWhileEditing];
    [txtInputField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
    [txtInputField setFont:[UIFont systemFontOfSize:12]];
    [txtInputField setReturnKeyType:UIReturnKeyDone];
    [txtInputField setTextAlignment:UITextAlignmentLeft];
    [txtInputField setKeyboardAppearance:UIKeyboardAppearanceDefault];
    [txtInputField setKeyboardType:UIKeyboardTypeNumbersAndPunctuation];
    [txtInputField setAutocorrectionType:UITextAutocorrectionTypeNo];
    [txtInputField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
    txtInputField.clearButtonMode = UITextFieldViewModeWhileEditing;
    [txtInputField setBorderStyle:UITextBorderStyleRoundedRect];
    txtInputField.textColor = [UIColor colorWithRed:56.0f/255.0f green:84.0f/255.0f blue:135.0f/255.0f alpha:1.0f];
    //[txtInputField addTarget:self action:@selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];     

    [cell.contentView addSubview:txtInputField];
    [txtInputField release];

} // end if


// Configure the cell...
//
//[self configureCell:cell atIndexPath:indexPath];


UILabel *label = (UILabel *)[cell viewWithTag:1];
[label setText:txt];

UITextField *txtField = (UITextField *) [cell viewWithTag:2];
[txtField setText:txtText];
[txtField setPlaceholder:txtPlaceholder];



return cell;
zardon
  • 2,910
  • 6
  • 37
  • 58