NSFetchedResultsController崩溃 - 可能是由于内存警告

时间:2011-10-11 08:43:32

标签: iphone ios uitableview core-data nsfetchedresultscontroller

(在2011-10-11 20:45 +02:00问题末尾添加了另一个更新)

我的应用程序(iPhone)出现了一个奇怪的问题。它有点随机崩溃(见下面的stacktrace)。

应用程序结构

app结构是一个UITabBarController,里面有几个UINavigationController。其中一个UINavigationControllers包含一个UITableView,它附有一个NSFetchedResultsController。

我正在从后台线程更新Core Data上下文(使用另一个上下文,然后将其合并到主上下文中)。

我正在为网络使用ASIHTTPRequest,为JSON部分使用TouchJSON(CJSONDeserializer)。

我还使用SafeFetchedResultsController作为UITableView,我的NSFetchedResultsControllerDelegate和SafeFetchedResultsControllerDelegate方法被进一步粘贴。

崩溃描述

我不确定导致崩溃的原因。我无法使用模拟器或在Xcode内的设备上启动和运行应用程序来重现它,但我已经能够在未连接到调试器的设备上重现它。

当应用程序从后台恢复时应用程序崩溃的那些时候,后台线程更新了Core Data上下文,我将tab切换到UITableView - 在应用程序崩溃之前,它已经空了半秒左右。

踪迹

这是stracktrace(来自使用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];
}

问题

主要问题是我目前不知道从哪里开始寻找错误,因为我无法弄清楚它的起源。希望有人可以解决这个问题。

需要有关此问题的更多信息?

只需添加评论哪些信息有用,我就会更新问题。

提前致谢!

更新(S)

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

这可能与它有关吗? 就像那样,核心数据正忙于在视图出现的那一刻处理更新。如果是这样,处理这样的问题的正确方法是什么?

//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

我不认为它实际上是我的应用程序导致内存警告,但我知道 - 它仍然必须能够处理它。

这就是didRecieveMemoryWarning的样子:

//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中),但是我不确定这个条件是否应该在这里或不。这真的可能是事故的原因吗?

在这种情况下,还有更好的方法来处理内存警告吗?

0 个答案:

没有答案