【问题标题】:Core data: Serious application error核心数据:严重应用错误
【发布时间】:2011-09-27 18:27:40
【问题描述】:

我正在完成我的 Core Data 应用程序并开始我的最终测试。

Everyfing 工作正常,除了一件事,它随机发生,我无法重现。

这是日志(启用 NSZombie):

2011-07-03 20:27:53.144 MYAPP[1882:707] -[__NSCFType controllerWillChangeContent:]: unrecognized selector sent to instance 0x4a4c490
2011-07-03 20:27:53.149 MYAPP[1882:707] Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[__NSCFType controllerWillChangeContent:]: unrecognized selector sent to instance 0x4a4c490 with userInfo (null)
2011-07-03 20:27:53.165 MYAPP[1882:707] CoreAnimation: ignoring exception: -[__NSCFType controllerWillChangeContent:]: unrecognized selector sent to instance 0x4a4c490

这里崩溃了:

NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; // IT'S OK
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"Kontrahent" inManagedObjectContext:context]; // IT'S OK
for(NSString *key in kontrahent) [newManagedObject setValue:[kontrahent valueForKey:key] forKey:key];  // IT'S OK
NSError *error = nil;
if (![context save:&error]) {  // IT'S NOT OK
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

我的动作层次结构:

1. Open application
2. Open my 'root' list (with NSFetchedResultsController, entity: "Faktura")
3. Tap 'Add' button
4. In my 'Add' view controller I create another object (entity: "Kontrahent")
5. I try to add it to database
6. It crashes / It doesn't.

SCHEME:

        +---[moc save:]---> Faktury (my root class)
        |                        ↓
        +-----delegate-- FakturaCreator <---[moc save:]--+  <--- HERE IT CRASHES
                                 ↓                       |
                         KontrahentCreator ---delegate---+

我知道它与NSFetchedResultsController[moc save:] 有关。但是我找不到我的问题,因为它会在需要时崩溃。有时它工作,有时它崩溃。如果您对这个问题有所了解,请帮助我:)


如果您需要更多代码...

NSFetchedResultsController 的东西(Faktury.m)

#pragma mark - Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController {
    
    if (__fetchedResultsController != nil) return __fetchedResultsController;
    
    // Setup the table
    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Faktura" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    
    // Setup the sort descriptors
    
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"NumerFV" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    
    // Create the fetched results controller
    
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
    
    [aFetchedResultsController release];
    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];
    
    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd Krytyczny" message:@"Wystąpił nieznany błąd przy zmienianiu zawartości w bazie danych. Dla dobra twoich danych prosimy niezwłocznie wyjść z aplikacji i spróbować ponownie." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
        
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    
    return __fetchedResultsController;
}    

#pragma mark - Fetched results controller delegate

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    
    if([[[controller sections] objectAtIndex:0] numberOfObjects] == 0) {
        emptySectionView.hidden = NO;
        UIBarButtonItem *editBtn = [[UIBarButtonItem alloc] initWithTitle:@"Edytuj" style:UIBarButtonItemStyleBordered target:self action:@selector(toogleEditing)];
        editBtn.enabled = NO;
        [self.navigationItem setLeftBarButtonItem:editBtn animated:NO];
        [editBtn release];
    } else {
        emptySectionView.hidden = YES;
        self.navigationItem.leftBarButtonItem.enabled = YES;
    }
    
    UITableView *table = tableView;
    
    switch(type) {
            
        case NSFetchedResultsChangeInsert:
            [table insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
            [table deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
            break;
            
        case NSFetchedResultsChangeUpdate:
            [self configureCell:(KSTableViewCell *)[table cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
            
        case NSFetchedResultsChangeMove:
            [table deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [table insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [tableView endUpdates];
}

当我点击添加按钮时(Faktury.m)

- (void)add:(id)sender {
    FakturaCreator *form = [[FakturaCreator alloc] init];
    form.hidesBottomBarWhenPushed = YES;
    form.delegate = self;
    form.managedObjectContext = self.managedObjectContext;
    [self.navigationController pushViewController:form animated:YES];
    [form release];
}

【问题讨论】:

  • 这是一个拆分视图控制器应用程序吗?
  • 你使用的是表格视图控制器吗?
  • 不,是UIViewController里面的UITableView。

标签: iphone core-data nsfetchedresultscontroller nsmanagedobjectcontext


【解决方案1】:

好的,我找到了我的问题。我有一个“KontrahentPicker”,它也有NSFetchedResultsController。但是这个UIViewController 显示为modalViewController。我打了我的Kontrahent,然后模态被解雇并释放了。但是NSFRC 的代表仍然处于活动状态。

我解决了我的问题

self.fetchedResultsController.delegate = nil;

-dealloc 方法中。

【讨论】:

  • 看,告诉你! ;) 虽然这个解决方案远非完美。如果 KontrahentPicker 是模态的,持有一个 NSFetchedResultsController 并且是它的委托,一旦它被解除,它应该与 NSFRC 实例一起被完全销毁。
  • 我的 dealloc 将委托设置为 nil,然后使用 NSMOC 释放 NSFRC。
  • 感谢您的回答!您刚刚为我节省了一个可能漫长的调试夜晚。
【解决方案2】:

看起来你持有一个指向一个对象的指针,该对象在你有机会使用它之前就从内存中删除了。确保您保留了任何会自动释放的对象。

从崩溃日志看来,NSFetchedResultsController 委托的指针指向已释放的内存。

FakturaCreator 和 KontrahentCreator 在保存时是否存在?将应用程序困在他们的 dealloc 方法中,看看那里是否一切正常。

【讨论】:

  • 是的,它们存在。 NSFetchedResultsController 在我的根目录中实现 - Faktury
  • NSFetchedResultsController 的委托是什么,您在代码中的什么位置设置它?
  • NSFRC的代表是Faktury
  • Faktury 是否创建 NSFetchedResultsController?您是否在NSFRC 发起时将Faktury 设置为代表? controllerWillChangeContent: 每次都被命中吗?它的代码是什么?我们可以做很多心理调试,但如果你给我们一些有助于解决问题的东西,它会更有效率。需要更多代码! ;)
  • 那么,controllerWillChangeContent: 是每次都被命中还是崩溃导致它偶尔不被命中?崩溃期间发送controllerWillChangeContent: 消息的对象是什么?
【解决方案3】:

如果您的任何核心数据对象中有 nil 值,也会发生这些崩溃。在保存之前查看每个对象以确保所有属性都有值是个好主意(即没有说 nil 或“...不是 nil ...”,这表明对象不符合 NSCoding 标准) .如果是这种情况,您可以简单地为属性添加一个默认值,使其永远不会为零,然后随时分配它们

【讨论】:

  • 我所有的值都不为零。但是如果我插入 nil abort() 就会被调用。
  • 不是 nil,因为它们都有值,或者它们中的任何一个实际上都说“not nil”?如果它说“not nil”,那将是一个问题。此外,尝试将 managedObjectContext 保存在代码的不同区域以查看导致崩溃的行可能是个好主意。尝试查找应用程序的功能,直到您确切地看到问题所在。考虑到你说它不会一直发生,我觉得这可能没有太大帮助,但肯定值得一试。
猜你喜欢
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多