1

I´m loading a bunch of countries to a table and allowing the user to delete. The rows directly correspond to the countries array, by using objectAtIndex:indexPath.row and I set the delete button´s tag to the same index.

When I delete the first couple of rows it´s ok but afterwards the wrong rows are getting deleted and the app crashes.

Here's how I create rows:

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
NSString *currentText;

// fill in country cell content 
if ([tableView tag] == 400) {
    cell = [tableView dequeueReusableCellWithIdentifier:@"SettingsCountryCell"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                      reuseIdentifier:@"SettingsCountryCell"];
        NSLog(@"is nil"); 
    } // it´s never nil

    currentText = [arrSelectedCountries objectAtIndex:indexPath.row];
    int currentRow = indexPath.row;

    UILabel *countryLabel = (UILabel *)[cell viewWithTag:401];
    countryLabel.text = currentText;

    // create button
    UIButton *countryButton = (UIButton *)[cell viewWithTag:402];

    [countryButton setTag:currentRow];
    [countryButton setTitle:[NSString stringWithFormat:@"row%d", currentRow] 
                   forState:UIControlStateNormal];
    NSLog(@"%@ - tag %d - title %@ - button tag %d", 
          currentText, 
          currentRow, 
          countryButton.titleLabel.text,
          countryButton.tag);

    // on load: Bulgaria - tag 2 - title row2 - button tag 2
    // after one deletion (and ever after): 
    //      Bulgaria - tag 1 - title (null) - button tag 0 

    [countryButton addTarget:self 
                      action:@selector(removeCountry:)
            forControlEvents:UIControlEventTouchUpInside]; 

}    

Here's how I remove them (i.e. countries):

- (void)removeCountry:(UIButton *)countryButton
{
// removed country
NSString *currentText = [arrSelectedCountries objectAtIndex:countryButton.tag];

NSLog(@"removed country %@ at tag %d", currentText, countryButton.tag);

// ok: removed country All CEE Countries at tag 0
// ok: removed country Bulgaria at tag 0
// not ok: removed country Czech Republic at tag 1

// add to picker selection and remove from selected
[arrCountries addObject:currentText];
[arrSelectedCountries removeObject:currentText];

// refresh picker and country table
[countryPicker reloadAllComponents];

[countryTable reloadData];

[countryTable reloadSections:[NSIndexSet indexSetWithIndex:0] 
            withRowAnimation:UITableViewRowAnimationFade];

// position table and elements below it
[self repositionForCountryChange]; 
}

At first the table is showing: row0, row1, row2, etc.

After a couple of deletions: row1, row2, row3, etc.

Once this happens, the label is no longer corresponding properly to the tag. When I click delete on Croatia, delete button labeled row 1, NSLog says:

removed country Czech Republic at tag 1

... and Croatia row is not deleted although its delete button now says row2.

And why am I getting from NSLog:

title (null) - button tag 0 

...when I can see in the table that there is a title and removeCountry can access button tag, although incorrectly?

C4 - Travis
  • 4,502
  • 4
  • 31
  • 56
Cekk
  • 159
  • 1
  • 2
  • 12

1 Answers1

0

You have set up the button with a tag to allow you to identify it as a subview in the cell (402) you then change the tag so it identifies the row the tag is in. When the cell is re-used, there is no view with tag 402, so your button is still identified with a tag number of its original row.

You're using tags for two purposes. Ideally, don't use them at all as they are fragile and do not make your code readable.

  • create a UITableViewCell subclass and identify its subviews using outlets
  • identify the row of the pressed button using the method I describe here which is much more flexible than tags and keeps working if you delete rows.
Community
  • 1
  • 1
jrturton
  • 118,105
  • 32
  • 252
  • 268
  • Thank you! It´s working now. You say not to use tagging at all but as you can see I use tags to identify the table if ([tableView tag] == 400) is there a better way of doing this then? – Cekk Mar 16 '12 at 02:54
  • Assuming you have more than one tableView in your view controller, hold a reference to it in an ivar or have an outlet to it, then have `if (tableView == self.countryTable)` or whatever But if it's working OK now, don't feel you have to change it! – jrturton Mar 16 '12 at 07:24