Search code examples
iosuitableviewdidselectrowatindexpathnsindexpath

didSelectRowAtIndexPath changes indexPath value every time I press the same row?


I was trying to change value if user push same table cell again and again.

In my didSelectRowAtIndexPath method, I create indexPath with value from didSelectRowAtIndexPath:indexPath method but this value changes every time I press the same table cell.

Is it normal?

My goal is when user push some table cell create NSObject with two properties (nameOfItem, numberOfItem). numberOfItem is default set to 1. I want to change this number +1 every time he push the same table cell.

Here is my code:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    NSString*nameForItem = [NSString stringWithFormat:@"%@", [self.ivc.objects objectAtIndex:indexPath.row]];
    Items *item = [Items new];
    [item setNameOfItem:nameForItem];
    [item setNumberOfItem:[NSNumber numberWithInt:1]];

    if (indexPath == self.index) {
        [item setNumberOfItem:[NSNumber numberWithInt:[item.numberOfItem integerValue]+1]]; 
    }

    self.index = indexPath;

Solution

  • I'm not sure about your real problem, and the goal what you'd like to achieve here... but I would improve your code-snippet like this:

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
        NSString*nameForItem = [NSString stringWithFormat:@"%@", [self.ivc.objects objectAtIndex:indexPath.row]];
        Items *item = [Items new];
        [item setNameOfItem:nameForItem];
        [item setNumberOfItem:[NSNumber numberWithInt:1]];
    
        // improving comparison
        if (indexPath.row == self.index.row && indexPath.section == self.index.section) {
            [item setNumberOfItem:[NSNumber numberWithInt:[item.numberOfItem integerValue]+1]]; 
        }
    
        // removing unnecessary instantiate and deep-copying the current index path
        self.index = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
    }
    

    issue #1

    while you comparing the actual pointers like:

    if (indexPath == self.index) { ... }
    

    you need to know the same instance of NSIndexSet can hold different row and section values (as per in my comment) as they are reused(!) by the UITableView, so you probably want to compare the actual indices rather than the pointers.


    issue #2

    while you retain the pointer for the index path like:

    self.index = indexPath;
    

    you need to be aware of the exact same thing I've mentioned one paragraph above, about the same instance of NSIndexPath can be and will be reused to present new indices.


    update

    if you wish to handle a counter for each index path (=rows in the current instance of the UITableView), you need to store those number somewhere permanently, in some collection.

    I'm not sure about the current environment, so I'm trying to present a generic solution for the problem.

    in your class you will need this (private) collection:

    NSMutableDictionary *_counters;
    

    and I would change your method like this, regarding I don't know what Items is, I chucked everything away entirely, that is I have currently:

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
        if (_counters == nil) _counters = [NSMutableDictionary dictionary];
        NSString *_key = [NSString stringWithFormat:@"%03ld:%03ld", (long)indexPath.section, (long)indexPath.row];
        NSInteger _currentCounterForIndexPath = [[_counters objectForKey:_key] integerValue];
        [_counters setObject:@(++_currentCounterForIndexPath) forKey:_key];
    }
    

    this will count the taps on each row for you, and increases the number of the taps every time for each row.

    the _counter dictionary will have the details like this (logged at a random stage of my test app):

    _counter : {
        "000:000" = 5;
        "000:001" = 1;
        "000:003" = 2;
        "000:004" = 6;
        "000:005" = 3;
        "000:006" = 1;
    }
    

    where the AAA:BBB is the key from the current section (AAA) and the current row (BBB), and the value is the number of taps.

    so, you can read that collection as

    • in section 0 the row 0 was tapped 5 times;
    • in section 0 the row 1 was tapped 1 times;
    • in section 0 the row 2 was tapped 0 times; (there is no record about any tap for this row!)
    • in section 0 the row 3 was tapped 2 times;
    • in section 0 the row 4 was tapped 6 times;
    • in section 0 the row 5 was tapped 3 times;
    • in section 0 the row 6 was tapped 1 times;

    later if you are curious to get the number of taps for a particular row in a particular section, you can reuse the code from my updated method, like e.g. for section 0, row 5:

    NSString *_key = [NSString stringWithFormat:@"%03ld:%03ld", 0, 5];
    NSInteger _currentCounterForIndexPath = [[_counters objectForKey:_key] integerValue];
    

    the _currentCounterForIndexPath will have the number of taps, which is 3 currently.

    I guess that is such simple.