Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 3 in section at index 0'

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

like image 634
Ron Pelayo Avatar asked Jul 31 '14 02:07

Ron Pelayo


2 Answers

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];
like image 53
quellish Avatar answered Nov 14 '22 15:11

quellish


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
}
like image 4
KBog Avatar answered Nov 14 '22 16:11

KBog