0

I'm trying to create a "like" button in my project. To detect current row (where the clicked button is) in UITableViewCell i'm using the following code:

-(void)likeBtnClick:(id)sender {
    UIButton *senderButton = (UIButton *)sender;
    NSLog(@"current Row=%d",senderButton.tag);
}

So, for the first cell NSLog shows

"current Row=203", for the second – "current Row=200", for the third – "current Row=197". But for the 4th row it is "current Row=203" again (5th – "current Row=200", 6th – "current Row=197", etc)!

And the same error repeats every 3 rows.

My question is - how to get the right number of the current row in UITableView?

UPDATE:

For Lyndsey Scott – cellForRowAtIndexPath method code:

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCell"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"NewsCell"];
    }
    [self.tableView setScrollsToTop:YES];
    [HUD hide:YES];
    Location *location = [_locations objectAtIndex:indexPath.row];
    UIButton *lkbut = (UIButton*) [cell viewWithTag:300];
    [lkbut setImage:[UIImage imageNamed:@"likehq2.png"] forState:UIControlStateNormal];

    NSInteger value = [location.information intValue];

    NSLog(@"val %ld", (long)value);

    lkbut.tag = value;
    NSLog(@"ur %@", location.user_like);
    [lkbut addTarget:self action:@selector(likeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    //...
    return cell;
}

Solution:

CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    NSLog(@"indexPath.row = %ld", (long)indexPath.row);

    NSLog(@"%lu", (unsigned long)[_locations count] - (long)indexPath.row);

"(unsigned long)[_locations count]" - is a number of your rows. //everyone has own code here

Thanks Anna, Lyndsey Scott and JOM!

dvijok
  • 89
  • 8
  • 2
    See http://stackoverflow.com/a/1802875/467105 for a better approach than tags. –  Aug 09 '14 at 13:41
  • I'v seen it, but the number like "0x00000016" is not what I need – dvijok Aug 09 '14 at 13:42
  • How do you see that text? How are you logging the resulting indexPath? Did you try `NSLog(@"indexPath.row = %d", indexPath.row);`? –  Aug 09 '14 at 13:44
  • 1
    Could you post the code from your cellForRowAtIndexPath method where you're setting the tags? – Lyndsey Scott Aug 09 '14 at 13:44
  • "-(void)likeBtnClick:(id)sender" is not in "-(UITableViewCell *)tableView", so indexPath is not declared there... – dvijok Aug 09 '14 at 13:46
  • Lyndsey Scott, see topic update – dvijok Aug 09 '14 at 13:49
  • @dvijok follow Anna's comment! thats the correct approach. Tags are very unreliable in this scenario. – CodingMeSwiftly Aug 09 '14 at 13:55
  • Seems like there's an issue with your location "information" values. – Lyndsey Scott Aug 09 '14 at 13:55
  • Actually, I think I know what's going on... Your buttons are being reused. – Lyndsey Scott Aug 09 '14 at 14:00
  • Using Anna's approach I've got the following in console: {length = 2, path = 0 - 3} But how can get only "3" (or 2, 1, 0) from "path = 0 - 3"? – dvijok Aug 09 '14 at 14:01
  • @dvijok, Look at the sample NSLog in my second comment. Don't log the whole indexPath object using `%@`. Use `indexPath.row` and `%d`. Using the `indexPath.row`, you can then get the data directly from your data source (`[_locations objectAtIndex:indexPath.row]`). –  Aug 09 '14 at 14:03
  • I seriously dislike running into code that uses obscure tags, it's bad coding habits. A much better concept would be to use a delegate callback (or a block callback). If you configure the cell with a block callback, just return the cell in the callback and you can use. Just configure the below in cell for row at index path: [cell configureWithStuff:(id)stuff withSelection:^(UITableViewCell *cell, BOOL selected) { NSIndexPath *index = [tableview indexPathForCell:cell]; } At that point, your code is very direct, precise, predictable, and not obscured. – TheCodingArt Aug 09 '14 at 14:44

2 Answers2

1

The reason you get same number again, is that tableview cells are being recycled. In your case it seems like there's max 3 rows on-screen at a time.

Anyway, here's my answer for similar question earlier: iPhone - How to determine in which cell a button was pressed in a custom UITableViewCell

Update: Anna has a good suggestion, which should work, too. Please check it out and see, it if works better.

Third way might be that you reset cell tag with indexPath.row, when you create/recycle a cell. There's always more than one way to do anything ;)

Community
  • 1
  • 1
JOM
  • 8,139
  • 6
  • 78
  • 111
  • 1
    Need to be careful with this superview method since the view hierarchy is different depending on iOS version. –  Aug 09 '14 at 14:07
  • Yeah, I don't agree with the method, but the assessment is right... – Lyndsey Scott Aug 09 '14 at 14:08
  • When I use this code, I get value from 0. But I have about 200 cells (or more). So how can I get values from highest to lowest? – dvijok Aug 09 '14 at 14:10
  • @dvijok Don't use this code. Use Anna's method. Just note that the reason your tags aren't working is because: "The reason you get same number again, is that tableview cells are being recycled. In your case it seems like there's max 3 rows on-screen at a time." – Lyndsey Scott Aug 09 '14 at 14:11
  • Ok, I've understood how to use Anna's method just now... :) But I still have the same question: "When I use this code, I get value from 0. But I have about 200 cells (or more). So how can I get values from highest to lowest?" – dvijok Aug 09 '14 at 14:16
  • Oh. I have a solution. If someone needs... NSLog(@"%lu", (unsigned long)[_locations count] - (long)indexPath.row); can help you. "(unsigned long)[_locations count]" - is a number of your rows. – dvijok Aug 09 '14 at 14:27
  • BTW, thanks Anna, Lyndsey Scott and JOM! :) – dvijok Aug 09 '14 at 14:28
0

I'd suggest this:

Firstly:

[lkbut addTarget:self action:@selector(likeBtnClick:) forControlEvents:UIControlEventTouchUpInside];

should be:

[lkbut addTarget:self action:@selector(likeBtnClick:andEvent:) forControlEvents:UIControlEventTouchUpInside];

and your button action methods should be:

-(void)likeBtnClick:(id)sender andEvent:(UIEvent*)event
{
    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:currentTouchPosition];

    NSLog(@"current Row=%d",indexPath.row);
}

Basically, no need to go through all that tag muck.

staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
  • No visible @interface for 'UITableView' declares he selector 'indexPathForItemAtPoint:'... – dvijok Aug 09 '14 at 15:37
  • @dvijok : whoops, sorry. `-indexPathForItemAtPoint:` is for a `collectionView`. for `tableView` it should be `-indexPathForRowAtPoint:` ...updated answer – staticVoidMan Aug 10 '14 at 11:38