Hi I'm having a hard time fixing this error.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 3 in section at index 0'
That error exist when I delete all my Entity in coredata and refetch it.
CALL API
self.fetchedResultsController = nil;
[NSFetchedResultsController deleteCacheWithName:nil];
[api requestForMenuCategory:@"details" managedObjectContext:self.managedObjectContext delegate:self];
EXECUTE WHEN API IS DONT FETCHING DATA
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"%@",[error description]);
}
else{
NSLog(@"NUMBER OF FETCH %d",[[_fetchedResultsController fetchedObjects] count]);
[_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];
[self.tableView reloadData];
}
Number of fetch says it's 0 but I dont' know why I still have a data in my tableview and after awhile it crashes
EDIT
Here's my number of row in section and I don't have number of section since default is 1 when not implemented
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[_fetchedResultsController fetchedObjects] count];
}
EDIT 2
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 3 in section at index 0'
*** First throw call stack:
(
0 CoreFoundation 0x00df65e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x042a08b6 objc_exception_throw + 44
2 CoreData 0x03310cae -[NSFetchedResultsController objectAtIndexPath:] + 398
3 DogDuck 0x0014c692 -[TestMenuViewController configureCell:atIndexPath:] + 146
4 DogDuck 0x0014c583 -[TestMenuViewController tableView:cellForRowAtIndexPath:] + 227
5 UIKit 0x01e2361f -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 412
6 UIKit 0x01e236f3 -[UITableView _createPreparedCellForGlobalRow:] + 69
7 UIKit 0x01e07774 -[UITableView _updateVisibleCellsNow:] + 2378
8 UIKit 0x01e05b1f -[UITableView _setNeedsVisibleCellsUpdate:withFrames:] + 171
9 UIKit 0x01e1b111 -[UITableView _rectChangedWithNewSize:oldSize:] + 490
10 UIKit 0x01e1b6dd -[UITableView setBounds:] + 279
11 UIKit 0x01daac17 -[UIScrollView setContentOffset:] + 690
12 UIKit 0x01e1c1d1 -[UITableView setContentOffset:] + 314
13 UIKit 0x01dc7cae -[UIScrollView(UIScrollViewInternal) _adjustContentOffsetIfNecessary] + 2622
14 UIKit 0x01daad82 -[UIScrollView setContentInset:] + 143
15 UIKit 0x01e1c302 -[UITableView setContentInset:] + 280
16 DogDuck 0x00133be6 -[EGORefreshTableHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:] + 310
17 DogDuck 0x0014c2a8 -[TestMenuViewController doneLoading] + 440
18 DogDuck 0x00006192 __66-[BoogieAPI requestForMenuCategory:managedObjectContext:delegate:]_block_invoke + 1266
19 Foundation 0x02ce2695 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 151
20 Foundation 0x02c42945 -[NSBlockOperation main] + 88
21 Foundation 0x02c9b829 -[__NSOperationInternal _start:] + 671
22 Foundation 0x02c18558 -[NSOperation start] + 83
23 Foundation 0x02c9daf4 __NSOQSchedule_f + 62
24 libdispatch.dylib 0x048ac4b0 _dispatch_client_callout + 14
25 libdispatch.dylib 0x0489a75e _dispatch_main_queue_callback_4CF + 340
26 CoreFoundation 0x00e5ba5e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
27 CoreFoundation 0x00d9c6bb __CFRunLoopRun + 1963
28 CoreFoundation 0x00d9bac3 CFRunLoopRunSpecific + 467
29 CoreFoundation 0x00d9b8db CFRunLoopRunInMode + 123
30 GraphicsServices 0x0524c9e2 GSEventRunModal + 192
31 GraphicsServices 0x0524c809 GSEventRun + 104
32 UIKit 0x01d34d3b UIApplicationMain + 1225
33 DogDuck 0x000027cd main + 125
34 DogDuck 0x00002745 start + 53
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
ADDITIONAL NOTE Cell for row is being called but fetchedobject is 0
The problem is inside your configureCell:atIndexPath
method. Unfortunately the implementation that is provided in the Core Data Xcode templates has a few bugs. Your crash is one of them.
The NSFetchedResultsController
method objectAtIndexPath:
is not very safe to call. If you give it an NSIndexPath that is out of range it will crash with the very exception you are seeing. This is mentioned in the class reference:
If indexPath does not describe a valid index path in the fetch results, an exception is raised.
This is just like access to an array: whenever you access an array by an index, you should do a bounds check first. A bounds check for objectAtIndexPath:
would look like:
id result = nil;
if ([[self.fetchedResultsController sections] count] > [indexPath section]){
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:[indexPath section]];
if ([sectionInfo numberOfObjects] > [indexPath row]){
result = [self.fetchedResultsController objectAtIndexPath:indexPath];
}
}
And that's a bit complicated, but necessary. That solves the exception.
The reason you are getting an exception is that the state of the NSFetchedResultsController is getting out of sync with the state of the tableview. When your crash happens the tableView just asked your delegate methods (numberOfSectionsInTableView
and tableView:numberOfRowsInSection:
for the number of rows and sections. When it asked that, the NSFetchedResultsController had data in it, and gave positive values (1 section, 3 rows). But in-between that happening and your crash, the entities represented by the NSFetchedResultsController were deleted from the NSManagedObjectContext. Now cellForRowAtIndexPath:
is being called with an outdated indexPath
parameter.
It looks like egoRefreshScrollViewDataSourceDidFinishedLoading
is causing the tableView to be rebuilt by adjusting the content view of the scroll view - and cellForRowAtIndexPath:
to be called - before you refetch and reload your tableView. That needs to happen before whatever egoRefreshScrollViewDataSourceDidFinishedLoading
is doing. egoRefreshScrollViewDataSourceDidFinishedLoading
is causing cellForRowAtIndexPath:
to be called with stale index paths.
The real problem may lie in your NSFetchedResultsControllerDelegate
methods. When your entities are being deleted, those should be getting called to remove items from the tableView. That does not seem to be happening here.
The short version though, move your [self.tableView reloadData];
up one line:
[self.tableView reloadData];
[_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];
Here's the helper method I wrote based on the accepted answer, but in Swift 3:
func validateIndexPath(_ indexPath: IndexPath) -> Bool {
if let sections = self.fetchedResultsController?.sections,
indexPath.section < sections.count {
if indexPath.row < sections[indexPath.section].numberOfObjects {
return true
}
}
return false
}
EDIT (USAGE)
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier(), for: indexPath)
if self.validateIndexPath(indexPath) {
configureCell(cell: cell, indexPath: indexPath)
} else {
print("Attempting to configure a cell for an indexPath that is out of bounds: \(indexPath)")
}
return cell
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With