Indexpathforrowatpoint Returns Nil Only for First Cell in a UItableview

NSIndexPath return nil

Try sending a delegate to the nextviewcontroller like

   DestinationViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DestinationViewController"];
controller.args=myArgs;
controller.delegate = self;
[self.navigationController pushViewController:controller animated:YES];

and when traversing back from that viewController to the present table viewcontroller pass that delegate.

This may help you...

tableView:indexPathForCell returns nil

It could be that the cell is not visible at this moment. tableView:indexPathForCell returns nil in this situation. I solved this using indexPathForRowAtPoint this method works even if the cell is not visible. The code:

UITableViewCell *cell = textField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];

iOS - indexPathForRowAtPoint don't return correct indexPath with different cell height

One way to do it would be to add a UILongPressGestureRecognizer to each UITableViewCell (that all use the same selector), then when the selector is called you can get the cell via sender.view. Perhaps not the most memory efficient, but if the single gesture recognizer won't return the right row in certain situations, this way should work.

Something like this:

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

...

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:@selector(handleLongPress:)];
[longPress setMinimumPressDuration:2.0];
[cell addGestureRecognizer:longPress];
[longPress release];

return cell;
}

then

- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {  
UITableViewCell *selectedCell = sender.view;
}

indexPathForCell returns nil since ios7

Your approach to find the "enclosing" table view cell of a text field is fragile,
because is assumes a fixed view hierarchy (which seems to have changed between
iOS 6 and iOS 7).

One possible solution would be to traverse up in the view hierarchy until the table view cell is found:

UIView *view = textField;
while (view != nil && ![view isKindOfClass:[UITableViewCell class]]) {
view = [view superview];
}
EditingCell *cell = (EditingCell *)view;

A completely different, but often used method is to "tag" the text field with the row
number:

cell.textField.tag = indexPath.row;   // in cellForRowAtIndexPath

and then just use that tag in the text field delegate methods.

indexPath is nil for DidSelectRowAtIndexPath when clicking on UITextField in cell

Using a similar method as this, you can get the index path of a UITextField in a cell as so:

-(NSIndexPath *)indexPathForTextField:(UITextField *)textField
{
CGPoint textFieldMiddle = CGPointMake(CGRectGetMidX(textField.bounds), CGRectGetMidY(textField.bounds));
CGPoint point = [textField convertPoint:textFieldMiddle toView:self.tableView];
return [self.tableView indexPathForRowAtPoint:point];
}

-(void)textFieldDidChange:(UITextField *)textField
{
NSIndexPath *indexPath = [self indexPathForTextField:textField];
// Now you can update the object at indexPath for your model!
}

This is neater than relying on tags or looking at superviews!

To answer the "Why did this change?" question...

iOS 7 UITableViewCell hierarchy is different as it now contains scroll views or something inside the cell to handle the swipe to delete.

Here's a dump of the view hierarchy in iOS 7:

<CustomTableViewCell: 0x8cbc9e0; baseClass = UITableViewCell; frame = (0 0; 320 44); autoresize = W; layer = <CALayer: 0x8cbcc50>>
| <UITableViewCellScrollView: 0x8c6ceb0; frame = (0 0; 320 44); autoresize = W+H; gestureRecognizers = <NSArray: 0x8c6d0c0>; layer = <CALayer: 0x8cbce50>; contentOffset: {0, 0}>
| | <UITableViewCellContentView: 0x8cb54e0; frame = (0 0; 320 44); gestureRecognizers = <NSArray: 0x8cbb990>; layer = <CALayer: 0x8cbb7f0>>
| | | <UILabel: 0x8cbbaf0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x8cbd000>>
| | | <UITableViewLabel: 0x8cbd210; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x8cbd360>>
| | <_UITableViewCellSeparatorView: 0x8cc2a10; frame = (15 43.5; 305 0.5); layer = <CALayer: 0x8cc26e0>>

iOS-indexPath always return nil

Try the below code

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// set Segue Identifier from your first viewcontroller to second viewController in stoaryboard
[self performSegueWithIdentifier:@"firstVCToSecondVCSegueIdentifier" sender:indexPath];
}

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"firstVCToSecondVCSegueIdentifier"])
{
if ([sender isKindOfClass:[NSIndexPath class]])
{
NSIndexPath *indexPath = (NSIndexPath *)sender;
if ([segue.destinationViewController isKindOfClass:[SecondVC class]]) {
SecondVC *aSecondVC = (SecondVC*)segue.destinationViewController;
NSString *name =self.nameArray[indexPath.row];
aSecondVC.title = name;
}
}
}
}

How to differenciate indexPath of first cell with indexPath of empty space at the end of table?

Is there a way to tell the difference between such a click, in the empty space at the end of the table, and a click on a "proper" cell of the table?

Yes. For the cheap and easy solution only do what you are trying to do if you actually get an indexPath:

 NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:p];
if(indexPath != nil){
// do everything in here
}

Basically, your indexPath is returning nil because it can't find a row. From the docs:

An index path representing the row and section associated with point, or nil if the point is out of the bounds of any row.

You could do it the way that you're currently doing it but is there any reason why you aren't using:

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

This is a much more standard way of detecting the cell that the user tapped on.

This method won't be called if you tap on something that isn't a cell and has a number of other benefits. Firstly you get a reference to the tableView and the indexPath for free. But you also won't need any gesture recognisers this way either.

Try something like this:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// Do stuff with cell here...
}

Obviously this all assumes that you have correctly set a class as your table view's delegate.

NB: It's very easy to mistakenly write didDeselectRowAtIndexPath instead of didSelectRowAtIndexPath when using Xcode's autocompletion to do this. I always do this and then inevitably realise my mistake 20 minutes later.



Related Topics



Leave a reply



Submit