(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).
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.
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.
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
#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 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.
Just add a comment on which information that would be helpful, and I'll update the question.
Thanks in advance!
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);
}
}
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?
User contributions licensed under CC BY-SA 3.0