Основные данные: серьезная ошибка приложения - PullRequest
4 голосов
/ 04 июля 2011

Я заканчиваю свое приложение Core Data и начинаю финальное тестирование.

Все работает нормально, кроме одной вещи, которая случается случайным образом , и я не могу воспроизвести ее.

Вот журнал (с NSZombieEnabled):

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:]. Но я не могу определить свою проблему, потому что она падает, когда захочет. Иногда работает, иногда падает. Если вы знаете что-то об этой проблеме, пожалуйста, помогите мне:)


ЕСЛИ ВАМ НУЖЕН БОЛЬШЕ КОДА ...

NSFetchedResults Контент контроллера (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];
}

Ответы [ 3 ]

6 голосов
/ 05 июля 2011

ОК, я обнаружил свою проблему. У меня есть «KontrahentPicker», и у него тоже NSFetchedResultsController. Но это UIViewController было представлено как modalViewController. Я вырвал свой Kontrahent, и модал был уволен и выпущен Но делегат NSFRC все еще был активен.

Я решил свою проблему, поставив

self.fetchedResultsController.delegate = nil;

в -dealloc метод.

0 голосов
/ 04 июля 2011

Эти сбои также могут возникать, если у вас есть нулевое значение в любом из ваших основных объектов данных.Было бы неплохо посмотреть на каждый объект перед сохранением, чтобы убедиться, что все свойства имеют значения (т. Е. Ничего не говорит nil или «... not nil ...», что указывает на то, что объект не совместим с NSCoding),Если это так, вы можете просто добавить значение по умолчанию для атрибутов, чтобы они никогда не равнялись нулю, а затем назначить их по мере продвижения

0 голосов
/ 04 июля 2011

Похоже, вы держите указатель на объект, который удаляется из памяти, прежде чем вы сможете использовать его. Убедитесь, что вы сохраняете все объекты, которые в противном случае были бы автоматически освобождены.

Из журнала сбоев это будет выглядеть как указатель делегата NSFetchedResultsController, указывающий на уже освобожденную память.

Существуют ли FakturaCreator и KontrahentCreator во время сохранения? Ловите приложение в их методах dealloc, чтобы увидеть, все ли там хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...