1

I am having a list displaying a name and a button titled as "Follow". When I tap on the button title should change to "UnFollow". If I tap on the button again the title should again change to "Follow". This is working fine, but when I am scrolling the table the title of the other cells are also changing due to cell reuse.

The code is as follows:

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *CellIdentifier = @"AuthorsListCell";
    AuthorsListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                                     forIndexPath:indexPath];
    dic_eachAuthor = [[_arr_authors objectAtIndex:indexPath.row] mutableCopy];

    cell.lbl_authorName.text = [dic_eachAuthor objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;

    if([dic_eachAuthor valueForKey:@"follow"]){
        [cell.btn_followOrUnfollow setTitle:@"UnFollow" forState:UIControlStateNormal];
    }
    else{

        [cell.btn_followOrUnfollow setTitle:@"Follow" forState:UIControlStateNormal];
    }

    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}


    -(void)followOrUnfollow:(UIButton *)sender
{
    if ([sender.titleLabel.text isEqualToString:@"Follow"]) {
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];
        [dic_eachAuthor setValue:@"1" forKey:@"follow"];

    }
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) {
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
        [dic_eachAuthor setValue:nil forKey:@"follow"];


    }


}

Please suggest something to prevent the cell reuse.

Shikhar varshney
  • 816
  • 1
  • 9
  • 23
  • add code for "if cell is nil" because everytime new cell is initialized. so you are facing this issue. cell = (ListTableViewCell *)[[ListTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: CellIdentifier]; – Kamal Bhardwaj Jun 22 '15 at 05:58
  • no, it does not solve the problem. – Shikhar varshney Jun 22 '15 at 06:12

5 Answers5

1

Add this condition in followOrUnfollow in cellForRowAtIndexPath also

if ([sender.titleLabel.text isEqualToString:@"Follow"]) {
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];

    }
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) {
        [sender setTitle:@"Follow" forState:UIControlStateNormal];


    }
Akshay Karanth
  • 347
  • 1
  • 13
0

Store follow/unfollow state information within datasource.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *CellIdentifier = @"CellIdentifier";
    ListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                                     forIndexPath:indexPath];

    cell.lbl_authorName.text = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;

    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];

    NSString *btnTitle = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"userFollowUnfollow"];
     [sender setTitle:btnTitle forState:UIControlStateNormal];

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

-(void)followOrUnfollow:(UIButton *)sender
{
    if ([sender.titleLabel.text isEqualToString:@"Follow"]) {
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];

    }
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) {
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
    }

    [[_arr_authors objectAtIndex:sender.tag]  setValue:sender.titleLabel.text forKey:@"userFollowUnfollow"];

}
Ruchish Shah
  • 319
  • 1
  • 6
0

When you originally populate the table row, you do it from an array here cell.lbl_authorName.text = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"name"];. The problem is that you don't populate the follow or unfollow information from this array. So all you are doing is toggling a button and there is no saving of the state of that button. What you need to do is modify the array to have a place to save the follow/unfollow state. Then populate the state in the table cell from this array. Then when you call followOrUnfollow: you need to modify the state in the array.

When the cell gets reused it goes and checks with the original array to populate it, populate the follow from the array and you will be set.

Edited to add some code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *CellIdentifier = @"CellIdentifier";
    ListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier                                                                     forIndexPath:indexPath];

    cell.lbl_authorName.text = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;
    if([[_arr_authors objectAtIndex:indexPath.row] valueForKey:@"follow"]){
          [cell.btn_followOrUnfollow setTitle:@"UnFollow" forState:UIControlStateNormal];
    else{
         [cell.btn_followOrUnfollow setTitle:@"Follow" forState:UIControlStateNormal];
    }

    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

-(void)followOrUnfollow:(UIButton *)sender
{
    if ([sender.titleLabel.text isEqualToString:@"Follow"]) {
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];
        [[_arr_authors objectAtIndex:sender.tag] setValue:1 forKey:@"follow"]
    }
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) {
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
        [[_arr_authors objectAtIndex:sender.tag] setValue:0 forKey:@"follow"]
    }
}

I am not at my normal machine, so the syntax is probably off, but you should get the idea. Also note you will have to add the follow property to _arr_authors

dstudeba
  • 8,878
  • 3
  • 32
  • 41
  • can u please show me how to do it with some code. Thanks for the suggestion. – Shikhar varshney Jun 22 '15 at 05:59
  • Added code sample for example, syntax is probably not right but concepts are there, good luck! – dstudeba Jun 22 '15 at 06:15
  • what should be the initial value of the follow key in the dictionary? – Shikhar varshney Jun 22 '15 at 06:28
  • Whatever your default value is, my guess is your default value is not following so it would be 0. – dstudeba Jun 22 '15 at 06:31
  • Please look at the edited code in the Question and it is still not working. Whenever I am scrolling back to the top the titles are again changing to "Follow" even after they were tapped. The bottom cells are however not changing the data now. Also the default value for follow key is nil – Shikhar varshney Jun 22 '15 at 06:47
0

You are missing something here, try this :

-(void)followOrUnfollow:(UIButton *)sender
{
    NSDictionary *dict = (NSDictionary *) _arr_authors[sender tag];
    if ([[dict objectForKey:@"name"] isEqualToString:@"Follow"]) 
     {
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];

     }
     else if ([[dict objectForKey:@"name"] isEqualToString:@"UnFollow"]) 
    {
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
    }
}
Kamal Bhardwaj
  • 948
  • 1
  • 10
  • 25
0

You are cells are reused so please implement this method in AuthorsListTableViewCell:

-(void) prepareForReuse{
  [super prepareForReuse];
  [self.btn_followOrUnfollow setTitle:@"Follow" forState:UIControlStateNormal];
}

// if the cell is reusable (has a reuse identifier), this is called just before the cell is returned from the table view method dequeueReusableCellWithIdentifier:. If you override, you MUST call super. And set the correct default value to the cell.

I also recommend to implement this way:

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *CellIdentifier = @"AuthorsListCell";
    AuthorsListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                                     forIndexPath:indexPath];

    cell.lbl_authorName.text = [dic_eachAuthor objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;

    [cell.btn_followOrUnfollow setTitle:@"Follow forState:UIControlStateNormal];
    [cell.btn_followOrUnfollow setTitle:@"UnFollow" forState:UIControlStateSelected];

    if([dic_eachAuthor valueForKey:@"follow"]){
        cell.btn_followOrUnfollow.selected = YES;
    } else{
        cell.btn_followorUnfollow.selected = NO;
    }
    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}


    -(void)followOrUnfollow:(UIButton *)sender
{
    sender.selected = !sender.selected;

    if ([sender.titleLabel.text isEqualToString:@"Follow"]) {
        [dic_eachAuthor setValue:@"1" forKey:@"follow"];
    }
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) {
        [dic_eachAuthor setValue:nil forKey:@"follow"];
    }


}

In AuthorsListTableViewCell

-(void) prepareForReuse{
  [super prepareForReuse];
  self.btn_followOrUnfollow.selected = NO;
}
agy
  • 2,804
  • 2
  • 15
  • 22