NSFetchedResultsController crashes – possibly due to memory warning

2

(Added another update at the end of the question at 2011-10-11 20:45 +02:00)

I'm having a strange issue with my app (iPhone). Where it somewhat randomly crashes (see stacktrace below).

App structure

The app structure is a UITabBarController with a couple of UINavigationController inside it. One of the UINavigationControllers contains a UITableView that has a NSFetchedResultsController attached to it.

I'm updating the Core Data context from a background thread (using another context and then merging this one into the main context).

I'm using ASIHTTPRequest for the networking and TouchJSON (CJSONDeserializer) for the JSON part.

I've also used SafeFetchedResultsController for the UITableView and my NSFetchedResultsControllerDelegate and SafeFetchedResultsControllerDelegate methods are pasted further down.

Description of the crash

I'm not sure what causes the crash. I have not been able to reproduce it using the simulator or when starting and running the app on a device from within Xcode, but I've been able to reproduce it on a device not attached to the debugger.

Those times the app crashed when it resumed from the background, the background thread updated the Core Data context and I switched tab to the UITableView - which was empty for half a second or so before the app crashed.

Stacktraces

This is the stracktrace (from using Bugsense.com):

CoreFoundation                      0x314d0987 __exceptionPreprocess   114
libobjc.A.dylib                     0x319a149d objc_exception_throw   24
CoreFoundation                      0x3147c0c1 -[__NSArrayM removeObjectAtIndex:]   300
CoreData                            0x352f6051 -[NSFetchedResultsController(PrivateMethods) _postprocessDeletedObjects:]   528
CoreData                            0x352f7efb -[NSFetchedResultsController(PrivateMethods) _postprocessUpdatedObjects:]   234
CoreData                            0x352fa2d7 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:]   1238
Foundation                          0x31cd8623 _nsnote_callback   142
CoreFoundation                      0x31457123 __CFXNotificationPost_old   402
CoreFoundation                      0x31456dc3 _CFXNotificationPostNotification   118
Foundation                          0x31cc7d23 -[NSNotificationCenter postNotificationName:object:userInfo:]   70
CoreData                            0x35256e3f -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:]   54
CoreData                            0x352b3569 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:]   140
CoreData                            0x3523f391 -[NSManagedObjectContext(_NSInternalChangeProcessing) _postRefreshedObjectsNotificationAndClearList]   76
CoreData                            0x3523f0bf -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:]   1814
CoreData                            0x35274b15 -[NSManagedObjectContext processPendingChanges]   16
CoreData                            0x352677a3 _performRunLoopAction   126
CoreFoundation                      0x31460c59 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__   16
CoreFoundation                      0x31460acd __CFRunLoopDoObservers   412
CoreFoundation                      0x314580cb __CFRunLoopRun   854
CoreFoundation                      0x31457c87 CFRunLoopRunSpecific   230
CoreFoundation                      0x31457b8f CFRunLoopRunInMode   58
GraphicsServices                    0x35d664ab GSEventRunModal   114
GraphicsServices                    0x35d66557 GSEventRun   62
UIKit                               0x338d5329 -[UIApplication _run]   412
UIKit                               0x338d2e93 UIApplicationMain   670
MyApp                               0x00002a75 0x0   10869
MyApp                               0x00002a40 0x0   10816

And this is the stacktrace from a crash log off the iPhone itself:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib          0x3076dd50 __semwait_signal_nocancel + 24
1   libsystem_c.dylib               0x35cc01d8 nanosleep$NOCANCEL + 112
2   libsystem_c.dylib               0x35c82c6c usleep$NOCANCEL + 36
3   libsystem_c.dylib               0x35c82c12 abort + 98
4   libstdc++.6.dylib               0x33f5fe48 __cxxabiv1::__terminate(void (*)()) + 64
5   libstdc++.6.dylib               0x33f5fe8a std::terminate() + 10
6   libstdc++.6.dylib               0x33f5ff5a __cxa_throw + 78
7   libobjc.A.dylib                 0x360f3c84 objc_exception_throw + 64
8   CoreFoundation                  0x31e1b206 -[__NSArrayM removeObjectAtIndex:] + 294
9   CoreData                        0x31a013c6 -[NSFetchedResultsController(PrivateMethods) _postprocessDeletedObjects:] + 522
10  CoreData                        0x31a01db8 -[NSFetchedResultsController(PrivateMethods) _postprocessUpdatedObjects:] + 228
11  CoreData                        0x31a039c0 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 1232
12  Foundation                      0x31a8617c _nsnote_callback + 136
13  CoreFoundation                  0x31e7f208 __CFXNotificationPost_old + 396
14  CoreFoundation                  0x31e19ee4 _CFXNotificationPostNotification + 112
15  Foundation                      0x31a835cc -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
16  CoreData                        0x319a5c00 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 48
17  CoreData                        0x319a5fc6 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 134
18  CoreData                        0x3196624a -[NSManagedObjectContext(_NSInternalChangeProcessing) _postRefreshedObjectsNotificationAndClearList] + 70
19  CoreData                        0x31965f78 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 1808
20  CoreData                        0x319a739e -[NSManagedObjectContext processPendingChanges] + 10
21  CoreData                        0x31941278 _performRunLoopAction + 120
22  CoreFoundation                  0x31e87a2e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 10
23  CoreFoundation                  0x31e8945e __CFRunLoopDoObservers + 406
24  CoreFoundation                  0x31e8a754 __CFRunLoopRun + 848
25  CoreFoundation                  0x31e1aebc CFRunLoopRunSpecific + 224
26  CoreFoundation                  0x31e1adc4 CFRunLoopRunInMode + 52
27  GraphicsServices                0x300c2418 GSEventRunModal + 108
28  GraphicsServices                0x300c24c4 GSEventRun + 56
29  UIKit                           0x35090d62 -[UIApplication _run] + 398
30  UIKit                           0x3508e800 UIApplicationMain + 664
31  MyApp           0x000022d2 main (main.m:13)
32  MyApp           0x00002290 start + 32

Thread 1 name:  Dispatch queue: com.apple.libdispatch-manager
Thread 1:
0   libsystem_kernel.dylib          0x3076efbc kevent + 24
1   libdispatch.dylib               0x31a6b094 _dispatch_mgr_invoke + 672
2   libdispatch.dylib               0x31a6c04a _dispatch_queue_invoke + 86
3   libdispatch.dylib               0x31a6b60a _dispatch_worker_thread2 + 190
4   libsystem_c.dylib               0x35c8b58a _pthread_wqthread + 258
5   libsystem_c.dylib               0x35c8bbbc start_wqthread + 0

Thread 2 name:  WebThread
Thread 2:
0   libsystem_kernel.dylib          0x3076bc00 mach_msg_trap + 20
1   libsystem_kernel.dylib          0x3076b758 mach_msg + 44
2   CoreFoundation                  0x31e882b8 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x31e8a562 __CFRunLoopRun + 350
4   CoreFoundation                  0x31e1aebc CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x31e1adc4 CFRunLoopRunInMode + 52
6   WebCore                         0x30b7137a RunWebThread(void*) + 378
7   libsystem_c.dylib               0x35c8a30a _pthread_start + 242
8   libsystem_c.dylib               0x35c8bbb4 thread_start + 0

Thread 3:
0   libsystem_kernel.dylib          0x3076bc00 mach_msg_trap + 20
1   libsystem_kernel.dylib          0x3076b758 mach_msg + 44
2   CoreFoundation                  0x31e882b8 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x31e8a562 __CFRunLoopRun + 350
4   CoreFoundation                  0x31e1aebc CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x31e5d6d2 CFRunLoopRun + 42
6   MyApp           0x0002b4fc +[ASIHTTPRequest runRequests] (ASIHTTPRequest.m:4290)
7   Foundation                      0x31a95382 -[NSThread main] + 38
8   Foundation                      0x31b075c6 __NSThread__main__ + 966
9   libsystem_c.dylib               0x35c8a30a _pthread_start + 242
10  libsystem_c.dylib               0x35c8bbb4 thread_start + 0

Thread 4:
0   libsystem_kernel.dylib          0x3076bc00 mach_msg_trap + 20
1   libsystem_kernel.dylib          0x3076b758 mach_msg + 44
2   CoreFoundation                  0x31e882b8 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x31e8a562 __CFRunLoopRun + 350
4   CoreFoundation                  0x31e1aebc CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x31e1adc4 CFRunLoopRunInMode + 52
6   Foundation                      0x31aa27f6 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 206
7   Foundation                      0x31a95382 -[NSThread main] + 38
8   Foundation                      0x31b075c6 __NSThread__main__ + 966
9   libsystem_c.dylib               0x35c8a30a _pthread_start + 242
10  libsystem_c.dylib               0x35c8bbb4 thread_start + 0

Thread 5 name:  com.apple.CFSocket.private
Thread 5:
0   libsystem_kernel.dylib          0x3076dc60 __select + 20
1   CoreFoundation                  0x31e8d8f2 __CFSocketManager + 582
2   libsystem_c.dylib               0x35c8a30a _pthread_start + 242
3   libsystem_c.dylib               0x35c8bbb4 thread_start + 0

Thread 6 Crashed:
0   libsystem_kernel.dylib          0x3076e3ec __workq_kernreturn + 8
1   libsystem_c.dylib               0x35c8b6d8 _pthread_wqthread + 592
2   libsystem_c.dylib               0x35c8bbbc start_wqthread + 0

Thread 7:
0   libsystem_kernel.dylib          0x3076e3ec __workq_kernreturn + 8
1   libsystem_c.dylib               0x35c8b6d8 _pthread_wqthread + 592
2   libsystem_c.dylib               0x35c8bbbc start_wqthread + 0

Thread 8:
0   libsystem_kernel.dylib          0x3076e3ec __workq_kernreturn + 8
1   libsystem_c.dylib               0x35c8b6d8 _pthread_wqthread + 592
2   libsystem_c.dylib               0x35c8bbbc start_wqthread + 0

Thread 6 crashed with ARM Thread State:
    r0: 0x00000004    r1: 0x00000000      r2: 0x00000000      r3: 0x00000000
    r4: 0x063da000    r5: 0x001701a4      r6: 0x063da000      r7: 0x063d9fe0
    r8: 0x00bda680    r9: 0x003fc0a0     r10: 0x3fb033f4     r11: 0x00000000
    ip: 0x00000170    sp: 0x063d9fc4      lr: 0x369536df      pc: 0x314363ec
  cpsr: 0x00000010

Delegate methods

#pragma mark -
#pragma mark fetchedResultsController

- (SafeFetchedResultsController*)fetchedResultsController {
    if(_fetchedResultsController !=nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSManagedObjectContext* theContext = [self context];

    NSEntityDescription* entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:theContext];
    [fetchRequest setEntity:entity];

    //Only events newer than 14 days
    NSDate* breakDate = [NSDate dateWithTimeIntervalSinceNow:(-1)*(14*24*60*60)];
    NSPredicate *p = [NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:@"startDate"] 
                                                        rightExpression:[NSExpression expressionForConstantValue:breakDate]
                                                               modifier:NSDirectPredicateModifier
                                                                   type:NSGreaterThanPredicateOperatorType
                                                                options:0];
    [fetchRequest setPredicate:p];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"startDateAsString" ascending:NO];
    NSSortDescriptor *sort2= [[NSSortDescriptor alloc] initWithKey:@"eventID" ascending:NO];
    NSSortDescriptor *sort3= [[NSSortDescriptor alloc] initWithKey:@"startDate" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sort,sort2,sort3,nil]];
    [fetchRequest setFetchBatchSize:12];

    SafeFetchedResultsController *theFetchedResultsController = [[SafeFetchedResultsController alloc] 
                                                               initWithFetchRequest:fetchRequest
                                                               managedObjectContext:self.context
                                                               sectionNameKeyPath:@"startDateAsString"
                                                               cacheName:nil];
    self.fetchedResultsController = theFetchedResultsController;
    [_fetchedResultsController setSafeDelegate:self];
    [_fetchedResultsController setDelegate:self];


    [sort release];
    [sort2 release];
    [sort3 release];
    [fetchRequest release];
    [theFetchedResultsController release];

    return _fetchedResultsController;
}

- (void)controllerDidMakeUnsafeChanges:(NSFetchedResultsController *)controller
{
    NSLog(@"Unsafe changes");
    [self.tableView reloadData];
}

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    if(controller == _fetchedResultsController) {
        [self.tableView beginUpdates];
    }

}

- (void)controller:(NSFetchedResultsController *)controller 
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo 
           atIndex:(NSUInteger)sectionIndex 
     forChangeType:(NSFetchedResultsChangeType)type {
    if(controller == _fetchedResultsController) {   
        switch(type) {

            case NSFetchedResultsChangeInsert:
                //if (!((sectionIndex == 0) && ([[self eventTable] numberOfSections] == 1)))
                [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                                 withRowAnimation:UITableViewRowAnimationFade];
                //              [[self eventTable] insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                //                               withRowAnimation:UITableViewRowAnimationNone];             
                break;
            case NSFetchedResultsChangeDelete:
                //if (!((sectionIndex == 0) && ([[self eventTable] numberOfSections] == 1) ))
                [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                                 withRowAnimation:UITableViewRowAnimationFade];
                //              [[self eventTable] deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                //                                   withRowAnimation:UITableViewRowAnimationNone];
                break;
        }
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    if(controller == _fetchedResultsController) {
        UITableView* tv = self.tableView;       

        switch(type)
        {
            case NSFetchedResultsChangeInsert:
            {
                //NSLog(@"Insert: %@", StringFromIndexPath(newIndexPath));

                [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                          withRowAnimation:UITableViewRowAnimationFade];
                //              [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                //                        withRowAnimation:UITableViewRowAnimationNone];
                break;
            }
            case NSFetchedResultsChangeDelete:
            {
                //NSLog(@"Delete: %@", StringFromIndexPath(indexPath));

                [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                          withRowAnimation:UITableViewRowAnimationFade];
                //              [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                //                        withRowAnimation:UITableViewRowAnimationNone];
                break;
            }
            case NSFetchedResultsChangeUpdate:
            {
                if (newIndexPath == nil)
                {
                    //NSLog(@"Update: %@", StringFromIndexPath(indexPath));

                    [tv reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                              withRowAnimation:UITableViewRowAnimationNone];
                }
                else
                {
                    //NSLog(@"Update: %@ -> %@", StringFromIndexPath(indexPath), StringFromIndexPath(newIndexPath));

                    [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                              withRowAnimation:UITableViewRowAnimationNone];

                    [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                              withRowAnimation:UITableViewRowAnimationNone];
                }

                break;
            }
            case NSFetchedResultsChangeMove:
            {
                //NSLog(@"Move: %@ -> %@", StringFromIndexPath(indexPath), StringFromIndexPath(newIndexPath));

                [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                          withRowAnimation:UITableViewRowAnimationFade];

                [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                          withRowAnimation:UITableViewRowAnimationFade];

                break;
            }
        }
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    if(controller == _fetchedResultsController) {
        [self.tableView endUpdates];
        //[self addNoEntriesFooterToTableViewIfNecessary:self.eventTable];
    }
    [self addNoEntriesFooterToTableViewIfNecessary:self.tableView];
}

The problem

The main problem is that I currently have no idea where to start looking for the error, since I can't figure out where it origins. Hopefully someone can shed some light on the problem.

Need more information about the problem?

Just add a comment on which information that would be helpful, and I'll update the question.

Thanks in advance!

Update(s)

2011-10-11 17:30 +02:00

Might this have something to do with it? Like that the Core Data is busy processing the updates at the very moment the view appears. If so, what's the proper way of handling a problem like that?

//myTableViewController.m
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSError *error2;
    if(![self.fetchedResultsController performFetch:&error2]) {
        NSLog(@"Unresolved error %@ %@",error2,[error2 userInfo]);
        exit(-1);
    }
}

2011-10-11 20:45 +02:00

I think I was able to recreate the crash with the console running (but not the app started through Xcode).

This is what the console reveals:

Oct 11 20:40:41 unknown myApp[754] <Warning>: Received memory warning. Level=2
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-06' not found in controller
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-06' not found in controller
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-08' not found in controller
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-11' not found in controller
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-06' not found in controller
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-11' not found in controller
Oct 11 20:40:42 unknown myApp[754] <Warning>: NSFetchedResultsController error: section '2011-10-11' not found in controller

I don't think that its actually my app causing the memory warning, but I know – it still has to be able to handle it.

This is what didRecieveMemoryWarning looks like:

//myTableViewController.m
- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    if([[self.navigationController viewControllers] count]>1) {

    } else {
        [super didReceiveMemoryWarning];
    }

    [detailController release];
    detailController = nil;

    // Relinquish ownership any cached data, images, etc. that aren't in use.
    [NSFetchedResultsController deleteCacheWithName:[_fetchedResultsController cacheName]];
}

I think the purpose of the [[self.navigationController viewControllers] count]>1 condition is to check that the view hasn't presented a child view (since it is inside a UINavigationController), but I'm not sure about whether this condition should be here or not. Could this really be the cause of the crash?

Are there any better way to deal with the memory warning in this case?

iphone
ios
uitableview
core-data
nsfetchedresultscontroller
asked on Stack Overflow Oct 11, 2011 by Manne W • edited Oct 11, 2011 by Manne W

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0