NSInvalidArgumentException when deleting cell using a different class

扶醉桌前 提交于 2020-01-07 02:35:11

问题


Update for code: Following on Matthew's answer I tried correcting my code to be more correct. Now the code does delete the cell but also crashes and gives an error:

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'

The code below is from an action called checkboxTapped which is in my CustomCell code. Once action is fired it gives the error. I figured out that my indexPath is equal to NULL, and thats most likely the issue. But I don't know how to fix it.

[self.textLabel setTextColor:[UIColor grayColor]];
[self.detailTextLabel setTextColor:[UIColor grayColor]];

parent = [[ViewController alloc] init];

db = [[DataObject alloc] init];
NSIndexPath *indexPath = [[parent tableView] indexPathForSelectedRow];

[[parent array] removeObjectAtIndex:[indexPath row]];
[db deleteTaskAtIndex:[indexPath row]];

[[parent tableView] deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

[db release];
[parent release];

Old: I looked through my code and I printed my array I was using and it appears to be fine, yet this error still persists.

* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM removeObjectAtIndex:]: index 1 beyond bounds [0 .. 0]'

My guess was that it had something to do with my indexPath but it doesn't make much different how much I change it.

-(void)checkboxTapped:(id)sender
{
    [sender setSelected:YES];

    [self.textLabel setTextColor:[UIColor grayColor]];
    [self.detailTextLabel setTextColor:[UIColor grayColor]];

    parent = [[ViewController alloc] init];
    UITableView *tableView = parent.tableView;
    NSMutableArray *array = [[NSMutableArray alloc] initWithArray:parent.array];
    [parent release];

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[array count] inSection:1];

    [array removeObjectAtIndex:[indexPath row]];
    [db deleteTaskAtIndex:[indexPath row]];    
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];

    [array release];

    [tableView endUpdates];
    [tableView reloadData];
}

回答1:


In your code [indexPath row] is going to return the value of [array count]. That's unlikely to be what you want. If your array has zero objects in it, you are going to attempt to remove the object at index 0. But there will be no objects and you'll get an error. If your array has 1 object in it, you're going to attempt to remove the object at index 1. Again, that will fail, because there is no object at index 1, just one object at index 0.

If you want to remove the last object in an array you need to use an index that is count-1. You may also need to check to see if the array is empty, if that case can occur.

Updated in response to follow up in comment

You don't want to do anything indexPathWithIndex. As a first step, try modifying your code along the following lines:

-(void)checkboxTapped:(id)sender
{
    [sender setSelected:YES];

    [self.textLabel setTextColor:[UIColor grayColor]];
    [self.detailTextLabel setTextColor:[UIColor grayColor]];

    parent = [[ViewController alloc] init];  // looks very odd - is an instance of this viewController active when the checkBox is tapped? If so, you don't want to create a new one, you want to access the existing one
    UITableView *tableView = parent.tableView;
    [parent release];  // this looks very dicey - when you release the parent, won't it release the tableView too?!

    int lastRow = [array count] - 1;
    if (lastRow == 0)
    {
         return; // bail if there are no rows in the table
    }

    NSMutableArray *array = [[NSMutableArray alloc] initWithArray:parent.array];
    [array removeObjectAtIndex: lastRow];  // not clear this will do anything as the reference to array is discarded later

    [db deleteTaskAtIndex: lastRow];   

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow: lastRow inSection:1]; 
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];

    [array release];

// [tableView endUpdates];  // there's no matching beginUpdates and you're only do one change operation anyway - leave this out

// [tableView reloadData]; // if you leave this line in, you won't see the delete animation - if you just want to delete one row, you wouldn't normally use reloadData, at least not if you want the animation
}

All this said, it looks as if there are other things going on here.

What's happening with array? You create this, remove an item from it and the discard the pointer to it. Is that what you really want to do. A more common pattern would be to get the pointer to the array from the other object and remove the item at the end of it here.

It's not clear from your code how you are updating the table's data source. When using deleteRowsAtIndexPaths:withRownAnimation you need to make sure the table's data source will return one row less than it did last time it was asked with tableView:numberOfRowsInSection:. From your code it's not clear how the tableView dataSource is going to know there's one less item, unless, perhaps, it's looking at whatever it is that db is pointing to in order to find this out.

More fundamentally, with a typical design pattern the tableView is going to be released when you release the parent view, so whatever it points to after `[parent release]' is going to do something undefined and is likely to crash at least some of the time.



来源:https://stackoverflow.com/questions/9452952/nsinvalidargumentexception-when-deleting-cell-using-a-different-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!