(Еще одно обновление в конце вопроса в 2011-10-11 20:45 +02: 00)
У меня странная проблема с моим приложением (iPhone). Там, где происходит случайное падение (см. Трассировку стека).
Структура приложения
Структура приложения представляет собой UITabBarController с парой UINavigationController внутри. Один из UINavigationControllers содержит UITableView, к которому прикреплен NSFetchedResultsController.
Я обновляю контекст Core Data из фонового потока (используя другой контекст, а затем объединяю его с основным контекстом).
Я использую ASIHTTPRequest для работы в сети и TouchJSON (CJSONDeserializer) для части JSON.
Я также использовал SafeFetchedResultsController для UITableView, а мои методы NSFetchedResultsControllerDelegate и SafeFetchedResultsControllerDelegate вставляются далее вниз.
Описание крушения
Я не уверен, что вызывает сбой. Я не смог воспроизвести его с помощью симулятора или при запуске и запуске приложения на устройстве из XCode, но я смог воспроизвести его на устройстве, не подключенном к отладчику.
В тех случаях, когда приложение выходило из строя, когда оно возобновлялось из фона, фоновый поток обновлял контекст Core Data, и я переключал вкладку на UITableView - который был пуст за полсекунды или около того, прежде чем приложение падало.
Stacktraces
Это прямая трассировка (с использованием 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
И это трассировка стека из журнала сбоя самого iPhone:
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];
}
проблема
Основная проблема в том, что в настоящее время я не знаю, с чего начать поиск ошибки, поскольку не могу понять, где она возникла. Надеюсь, кто-то сможет пролить свет на эту проблему.
Нужна дополнительная информация о проблеме?
Просто добавьте комментарий, какая информация будет полезна, и я обновлю вопрос.
Заранее спасибо!
* * Обновление тысячи сорок-девять (ы)
2011-10-11 17:30 +02: 00
Может быть, это как-то связано с этим?
Например, Core Data занята обработкой обновлений в тот самый момент, когда появляется представление. Если да, то как правильно решить такую проблему?
//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
Я думаю, что смог воссоздать сбой при работающей консоли (но не приложение, запущенное через XCode).
Вот что показывает консоль:
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
Я не думаю, что это на самом деле мое приложение вызывает предупреждение о памяти, но я знаю - оно все еще должно быть в состоянии справиться с этим.
Вот как выглядело ReecieveMemoryWarning:
//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]];
}
Я думаю, что цель условия [[self.navigationController viewControllers] count]>1
состоит в том, чтобы проверить, что представление не представляет дочернее представление (так как оно внутри UINavigationController), но я не уверен, должно ли это условие быть здесь или нет , Может ли это быть причиной аварии?
Есть ли лучший способ справиться с предупреждением памяти в этом случае?