I am trying to update the uicollection view whenever I delete a item. All the cells are deleting fine but if I delete the last cell in that collection view App crashes and I have put
[self.collectionview performBatchUpdates:^{
[postarray removeObjectAtIndex:indexPath.item];
[self.collectionview deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row inSection:1]]];
} completion:^(BOOL finished) {}];
The error I got is 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 17 beyond bounds [0 .. 16]' . Even array and collection view item starts at same index,I got this message
I was getting the same error message with the same lines of code, and it turned out it had nothing to do with the UICollectionView data source, but with a parallel array in another part of the app that updated its contents after but not its active index after the delete.
To find errors like this, enable Exception breakpoints: NSRangeException when deleting last UICollectionViewCell
Just inverse your two lines. You need to remove cell before to remove your object.
[self.collectionview performBatchUpdates:^{
[self.collectionview deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row inSection:1]]];
[postarray removeObjectAtIndex:indexPath.item];
} completion:^(BOOL finished) {}];
Related
I have a UICollectionView with 1 section. The user can delete cells from the collection, and I use this code for removal:
[self.collectionView performBatchUpdates:^{
[self.collectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:i inSection:0]]];
[self.media removeObjectAtIndex:i];
} completion:nil];
This works fine for every cell except for the last cell in the collection, which crashes the app every time with the error: Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 3 beyond bounds [0 .. 2]
NSZombies aren't showing me a stack trace so I put a breakpoint on every line in my code that accesses an array but none were hit, and I found that this error is thrown after deleteItemsAtIndexPaths, numberOfSectionsInCollectionView and sizeForItemAtIndexPath, but before numberOfItemsInSection and cellForItemAtIndexPath
What could be causing this crash? How can I debug it?
There are some similar SO posts, but this one from 2 years ago has no answer UICollectionView crash when deleting last item, and this one only solves the problem if you want to delete the whole section: Removing the last Cell in UICollectionView makes a Crash
UPDATE, here are the data source delegate methods that run before the crash:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(floorf(screenWidth/3), 200);
}
Just put the Exceptions Breakpoint and you'll find where exactly it is crashing.
Here is some of my code
NSArray *selectedRows = [self.playHistoryTableView indexPathsForSelectedRows];
if (selectedRows.count) {
for (NSIndexPath *selectionIndex in selectedRows)
{
OneSery *sery = [self.playHistoryDic objectAtIndex:selectionIndex.row];
[CoreDataManager deleteOneHistoryBySeryId:sery.seryId andVideoId:sery.latestVideo.videoId];
[self.playHistoryDic removeObjectAtIndex:selectionIndex.row];
}
[self.playHistoryTableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
}
When select the cells one at a time, it works well. But when multiselect the cell it gonna to crash like this:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
I know what it mean but I have no idea where I am wrong. And I tried, when it had three cells and I select the first and second to delete, it delete the first and third cell. When it had only two cells, I select both of them to delete, it does crash my app.
When I debug it, even the Onesery *sery value is wrong. So, how could selectionIndex is wrong while selectedRows is right?
Great thanks to #Wain it's finally done with those:
NSArray *selectedRows = [self.playHistoryTableView indexPathsForSelectedRows];
NSMutableIndexSet *indicesOfItemsToDelete = [[NSMutableIndexSet alloc] init];
if (selectedRows.count) {
for (NSIndexPath *selectionIndex in selectedRows)
{
OneSery *sery = [self.playHistoryDic objectAtIndex:selectionIndex.row];
[CoreDataManager deleteOneHistoryBySeryId:sery.seryId andVideoId:sery.latestVideo.videoId];
[indicesOfItemsToDelete addIndex:selectionIndex.row];
}
[self.playHistoryDic removeObjectsAtIndexes:indicesOfItemsToDelete];
[self.playHistoryTableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
}
In your loop you're doing
[self.playHistoryDic removeObjectAtIndex:selectionIndex.row];
so you're changing the list of items. On each iteration you try to access an item, but after the first item the next one has moved, because you removed one. For each subsequent item this is worse.
Eventually you get to a point where you try to access an item but so many have been removed that you go past the end of the list, then you crash.
You should get an array of the items to be removed in your loop and remove them all at once after the loop has completed.
I am trying to remove a cell from my collectionView, however. When I remove the object from my datasource and attempt a batchupdate, it says the cell doesn't exist anymore.:
'NSInternalInconsistencyException', reason: 'attempt to delete item 0 from section 0 which only contains 0 items before the update'
Before this code I remove the content from my core data, and the line [[usermanager getSelectedUser]loadCards]; actually reloads the datasource containing the content for the cells by getting them from the Core Data.
- (void)cardRemoved:(NSNotification *)note {
NSDictionary *args = [note userInfo];
Card *card = [args objectForKey:#"card"];
[[usermanager getSelectedUser]loadCards];
[self.collectionView performBatchUpdates:^{
NSIndexPath *indexPath =[NSIndexPath indexPathForRow:card.position.intValue inSection:0];
[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
} completion:^(BOOL finished){
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView reloadData];
}];
}
If I print out the amount of Cells before I call the loadCards line, I get the correct amount of rows(As expected).
EDIT
This is what loadCards calls:
-(NSMutableArray *)getCards{
UserModel *selectedUser = [self getSelectedUserFromDB];
NSMutableArray *cards = [[NSMutableArray alloc] init];
for(CardModel *cardModel in selectedUser.cards){
[cards addObject:[self modelToCard:cardModel]];
}
return cards;
}
I noticed, even if I don't call the loadCards method, It says there are no items in the view.
Can anyone help me out? Thank you
Remove the cells from the UICollectionView, then remove them from the model. The same thing applies to UITableView. You also don't need to reload the collection view after removing items.
If you prefer you can just remove items from the model and then reload the collection view and the items that aren't in the model will disappear from the collection view, but without the same animation that comes from removing items from a collection view.
I implemented the commitEditingStyle method to delete a row from my tableview. If I simply put [timersArray removeObjectAtIndex:indexPath.row] the row deletes just fine. The only problem is that it does not animate so I tried putting this:
[self->tableView beginUpdates];
[self->tableView deleteRowsAtIndexPaths:timersArray withRowAnimation:UITableViewRowAnimationBottom];
[self->tableView endUpdates];
but when I try and delete something it brings up this:
'NSInvalidArgumentException', reason: '-[Timer row]: unrecognized selector sent to instance 0x17ed37b0'
I thought it was because the timersArray is a NSMuttableArray and not a NSArray but that did not change anything. Can someone help me find out how to fix this? Anything will help. Thanks!
I fixed the issue by adding [NSArray arrayWithObject:indexPath] in place of timersArray in order for that to work I had to place the [timersArray removeRowAtIndex:indexPath.row] above the [self->tableView beginUpdates] and at that point it worked!
I am trying to insert a new cell into _myMusicCollectionView. Datasource is SharedAppDelegate.myMusics array:
[_myMusicsCollectionView performBatchUpdates:^{
[SharedAppDelegate.myMusics addObject:c.item];
[_myMusicsCollectionView insertItemsAtIndexPaths:[[NSArray alloc] initWithObjects:[NSIndexPath indexPathForRow:SharedAppDelegate.myMusics.count-1 inSection:0], nil]];
} completion:^(BOOL finished) {
[_musicStoreCollectionView reloadItemsAtIndexPaths:[[NSArray alloc] initWithObjects:indPath, nil]];
}];
I am getting:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for index path for global index 805306367 when there are only 1 items in the collection view'
Where am I wrong?
As you can read in the reason of the error you are accessing a cell at index 805306367. Probably this means SharedAppDelegate.myMusics.count-1 is negative or indPath contains wrong values.