NSInternalInconsistencyException for UITableView when using UICollectionView? - ios

I was trying to insert items into a collection view with this code:
- (IBAction)addCards:(UIButton *)sender {
int numberOfCardsToAdd = EXTRA_CARDS_NUMBER;
if ([[self.collectionView visibleCells] count] == 0) {
numberOfCardsToAdd = self.startingCardCount;}
// loop through the game model, draw random cards from the deck and assign it to the array
// take into account the "no cards left in deck" case
for (int i = 0; i < numberOfCardsToAdd; i++) {
if (![self.game.deck isEmpty]) {
SetsCard *cardToAdd = (SetsCard *) [self.game.deck drawRandomCard];
if (cardToAdd) [self.game.cards addObject:cardToAdd];
NSIndexPath *newObject = [[NSIndexPath alloc] initWithIndex:[self.game.cards indexOfObject:cardToAdd]];
[self.collectionView insertItemsAtIndexPaths:#[newObject]]; // adding card to view
}
}
[self.collectionView reloadData];
}
and I got this error:
Assertion failure in -[NSIndexPath row], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableViewSupport.m:2680
2013-06-13 09:09:12.443 Improved Matchismo[1206:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.'
*** First throw call stack:
(0x1cb1012 0x10eee7e 0x1cb0e78 0xb84665 0x29eb6c 0x54b14d 0x53fd69 0x53e60e 0x53e646 0x926e 0x1102705 0x362c0 0x36258 0xf7021 0xf757f 0xf66e8 0x65cef 0x65f02 0x43d4a 0x35698 0x1c0cdf9 0x1c0cad0 0x1c26bf5 0x1c26962 0x1c57bb6 0x1c56f44 0x1c56e1b 0x1c0b7e3 0x1c0b668 0x32ffc 0x269d 0x25c5)
libc++abi.dylib: terminate called throwing an exception
which really confuses me because I was adding items to an UICollectionView, not an UITableView, and my app does not use any instance of UITableView at all. Does anyone know why I got this error, and how I can fix it?
Thanks very much in advance!

A collection view works with two-level index paths (section/row) in the same way as
a table view, so you should create the index path
NSIndexPath *newObject = [NSIndexPath indexPathForRow:... inSection:0];
if there is only one section (section 0).
-[NSIndexPath row] is declared in the #interface NSIndexPath (UITableView) category and the error message has probably not been changed when collection views were introduced in iOS 6, so the message "Invalid index path for use with UITableView" is misleading.

Related

Why I use indexPathsForSelectedRows to get all cell selected to delete but crashed my app?

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.

UICollectionView insertSections error - NSInvalidArgumentException reason setObjectForKey object cannot be nil UICollectionViewItemKey

I'm getting an error using a UICollectionView as follows:
2013-11-29 17:29:07.832 Clients[34200:70b]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** setObjectForKey: object cannot be nil
(key: <_UICollectionViewItemKey: 0x8da14f0>
Type = DV ReuseID = (null) IndexPath = (null))'
And the code is as follows, where I essentially have two NSMutableArrays -- one containing all entries and the other used to reduce the entries to one section -- in this bit, I'm adding all the missing sections back in (hope that makes sense).
[self.collectionView performBatchUpdates:^{
NSString *selectedMarketSector = [[[[_marketSectors objectAtIndex:0] clients] objectAtIndex:0] clientMarketSector];
NSMutableIndexSet *insertSections = [[NSMutableIndexSet alloc] init];
for (TBMarketSector* sector in _allMarketSectors) {
if (![[[[sector clients] objectAtIndex:0] clientMarketSector ] isEqualToString:selectedMarketSector]) {
[insertSections addIndex:[_allMarketSectors indexOfObject:sector]];
}
}
_marketSectors = [self.allMarketSectors mutableCopy];
[self.collectionView insertSections:insertSections];
} completion:^(BOOL finished) {
[self setLayoutStyle:TBLayoutStacks animated:YES];
}];
The line that 'appears' to be causing the problem is the [self.collectionView insertSections:insertSections]; but I'm wondering if there is something weird going on elsewhere...
Thanks for any assistance you can provide.
Believe it or not, it seems this particular issue is actually relating to a UICollectionElementKindSectionFooter that I don't want.
I should have mentioned that this only started being a problem with iOS7 (not the first problem I've had with Collection Views after switching to iOS 7 either).
Anyway, my custom UICollectionViewFlowLayout implemented the - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath method and was returning some attributes for all supplementary views.
To fix this particular problem, I needed to add the following:
if ([kind isKindOfClass:[UICollectionElementKindSectionFooter class]])
return nil;
Thanks.
This kind of crash can be if in method
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
You try to get in dequeueReusableSupplementaryView(ofKind: - view of type elementKindSectionHeader, when kind is elementKindSectionFooter.
Check is nib register for current kind.
Thanks.

insertRowsatIndexPath exception iOS

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update'
I realize the issue here is that I am trying to add a cell to the tableView but it doesn't want it isn't adding one and I can't figure out why.
- (IBAction)addNewIngredient: (id) sender
{
NSString *newIngredient = [recipe createIngredient];
[[recipe ingredients]addObject:newIngredient];
//figure out where that item is in the array
int lastRow = [[recipe ingredients]indexOfObject: newIngredient];
NSIndexPath *ip = [NSIndexPath indexPathForRow:lastRow inSection:0];
NSLog(#"Added a new ingredient!");
[[self tableView] insertRowsAtIndexPaths:[NSArray arrayWithObject:ip] withRowAnimation:
UITableViewRowAnimationTop];
}
To clarify what I'm trying to do here:
recipe has a property ingredients which is an array of NSStrings.
I am adding an object to the ingredients array (does this automatically increase the array count or do I have to do it manually?)...
Then I'm figuring out where that item is in the array with "int lastRow = [[recipe ingredients]indexOfObject:newIngredient]"
Then getting an index path to point there. and then inserting that ingredient into the tableView.
The reason for your exception is that when you insert the row, your numberOfRowsInSection will be called again.
At that time, your data needs to be updated so that if you had 0 rows and are inserting one into it, the function returns 1

How to jump to the next row in detailview

i have a TableView which loads a detailview in didSelectRow. I have no problems with the data's.
I am using coreData and to populate the TableView i am using a NSFetchedResultsController.
Now, i want to make a next and previous function in the detailView to jump to the next or previous Table(row) Element. Next Previous like in the Mail-App.
I know that i have to use a button with IBAction.
But how can i make this function?
thanks,
brush51
Edit 1:
I have it done so:
- (IBAction) previousCard:(id) sender {
NSLog(#"previousBtn");
DashboardViewController *parent = (DashboardViewController *)self.parentViewController;
NSIndexPath *actualIndexPath = selectedRow2;
NSIndexPath * newIndexPath = [NSIndexPath indexPathForRow:actualIndexPath.row-1 inSection:actualIndexPath.section];
NSLog(#"newIndexPath: %#", newIndexPath);
[parent.tableViews selectRowAtIndexPath:newIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle]; //HERE I GET SIGABRT
}
But i get an error:
-[UIViewController tableViews]: unrecognized selector sent to instance 0xd758ae0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController tableViews]: unrecognized selector sent to instance 0xd758ae0'
How to solve this?
With your UITableView, you can get the selected row by:
- (NSIndexPath *)indexPathForSelectedRow
And set the selection by incrementing the indexPath.row:
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
then you action could be:
-(IBAction)nextCell:(id)sender {
NSIndexPath * actualIndexPath = myTableView.indexPathForSelectedRow;
NSIndexPath * newIndexPath = [NSIndexPath indexPathForRow:actualIndexPath.row+1 inSection:actualIndexPath.section];
[myTableView selectRowAtIndexPath:newIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}
for that you can manage with your DataSource array.
when you load your detail view at that time you pass your index of array(indexPath.row). by that index you fetch data in detail view. and using increment and decrement in that index you get data for next and previous cell.
Steps
1) setup your tableView.
2) when redirect to DetailView at that time set one int variable for store current indexPath.row . so define one int in detail View.
3) using next and previous button manage indexpath.row which is in int variable.
and represent appropriate data from Source array.
You can use:
(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
To get the cell you want (next or previous).
And then set the returned cell "Selected" property to YES.
cell.selected = YES

How to get indexPath.row of tableView which is currently being displayed?

I have a tableView with many values.
I want to get the first indexPath.row value of the table which is being displayed currently.
How can I do that?
I get Following Error while implementing krishnabhadra's answer:
Line at which the error comes is:
[self.table scrollToRowAtIndexPath:indexVis atScrollPosition:UITableViewScrollPositionTop animated:YES];
ERROR:
Assertion failure in -[NSIndexPath row], /SourceCache/UIKit_Sim/UIKit-1447.6.4/UITableViewSupport.m:2018
2011-04-01 11:57:25.458 GlossaryPro[1525:207] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.'
What could be wrong?
You can use tableView indexPathsForVisibleRows function, which returns an NSArray of NSIndexPath for all visible UITableViewCell. From indexPath.row you can find your array index.
NSArray *visible = [tableView indexPathsForVisibleRows];
NSIndexPath *indexpath = (NSIndexPath*)[visible objectAtIndex:0];
indexPath.row will give you index of first object displayed.
[self.myTableView visibleCells];
NSArray *anArrayOfIndexPath = [NSArray arrayWithArray:[self.myTableView indexPathsForVisibleRows]];
NSIndexPath *indexPath= [anArrayOfIndexPath lastObject];
Hope this will help you.
you can use indexPathsForVisibleRows
Returns an array of index paths each identifying a visible row in the receiver.
- (NSArray *)indexPathsForVisibleRows
Return Value
An array of NSIndexPath objects each representing a row index and section index that together identify a visible row in the table view. Returns nil if no rows are visible.
You can use: [self.tableView visibleCells]
That will return a nsarray of UITableViewCell objects, each representing a visible cell in the receiving table view.
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UITableView_Class/Reference/Reference.html
Get exact index number at center currently being displayed:
let middleIndex = ((tableView.indexPathsForVisibleRows?.first?.row)! + (tableView.indexPathsForVisibleRows?.last?.row)!)/2
Example:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let middleIndex = ((tableView.indexPathsForVisibleRows?.first?.row)! + (tableView.indexPathsForVisibleRows?.last?.row)!)/2
print(middleIndex)
}

Resources