Проблема с NSFetchedResultsController и вставкой записей - PullRequest
2 голосов
/ 21 февраля 2011

Хорошо, это сводит меня с ума, и я перепробовал все, что могу найти в Интернете, как возможное решение, но все еще ничего. Итак, вот моя ситуация: У меня есть вид, на котором есть кнопка. При касании это выскакивает список клиентов для выбора пользователя. когда они выбирают его, я использую контроллер fetchedresults, чтобы получить детали, связанные с клиентом, и отобразить их в виде таблицы. Это все хорошо работает. проблема заключается в том, что если я выбрал клиента A и вставил новую деталь, затем перешел к клиенту B и вставил новую деталь, когда я повторно выбрал клиента A и попытался вставить другую деталь, приложение вылетает со следующей ошибкой:

* Ошибка подтверждения в - [UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1447.6.4/UITableView.m:976 2011-02-21 10: 39: 12.896 SalesPro [36203: 207] Серьезный Ошибка приложения. Исключение было пойман от делегата NSFetchedResultsController во время вызовите -controllerDidChangeContent :. Неверное обновление: неверное количество строк в разделе 0. Количество строк содержится в существующем разделе после обновление (1) должно быть равно количество строк, содержащихся в этом раздел до обновления (1), плюс или минус количество вставленных строк или удалено из этого раздела (1 вставлено, 0 удалено). с userInfo (ноль) 2011-02-21 10: 39: 12.907 SalesPro [36203: 207] * Завершение приложение из-за неисследованного исключения «NSRangeException», причина: «- [UITableView scrollToRowAtIndexPath: atScrollPosition: анимированные]: строка (1) за пределами (1) для сечения (0) ".

Код, который обрабатывает выбор Клиента

-(void) CustomerSelectedRaised:(NSNotification *)notif
{
    NSLog(@"Received Notification - Customer Selected");
    selectedCustomer = (Customer *)[notif object];
    [self buildCustomerInfoText];
    if (popoverController != nil) {
        [popoverController dismissPopoverAnimated:YES];
    }

    fetchedResultsController = nil;

    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        //Update to handle error appropriately
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1); //fail
    }

    [self.partsListGrid reloadData];
}

FetchedResults Код контроллера

#pragma mark -
#pragma mark Fetch results controller

- (NSFetchedResultsController *)fetchedResultsController {
    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    //set-up fetched results controller
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"PartsList" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    [fetchRequest setFetchBatchSize:20];
    NSLog(@"TAMS ID: %@", selectedCustomer.customerTAMSID);
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"customerTAMSID == %@", selectedCustomer.customerTAMSID]]; 

    //set to sort by customer name
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sortOrder" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];   
    [fetchRequest setSortDescriptors:sortDescriptors];

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] 
                                                             initWithFetchRequest:fetchRequest 
                                                             managedObjectContext:[self managedObjectContext] 
                                                             sectionNameKeyPath:nil cacheName:nil];
    [aFetchedResultsController setDelegate:self];
    [self setFetchedResultsController:aFetchedResultsController];

    //clean-up
    [aFetchedResultsController release];
    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];

    //return results
    return fetchedResultsController;
}

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

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // In the simplest, most efficient, case, reload the table view.
    [[self partsListGrid] endUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.partsListGrid;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath withHeight:tableView.rowHeight];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.partsListGrid insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [self.partsListGrid deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeMove:
            break;
        case NSFetchedResultsChangeUpdate: 
            break;
        default:
            break;
    }
}

Добавить код изделия

-(void) addScannedPart:(Part *)part 
{
    // Check to see if entered part is already in list
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *partsEntity = [NSEntityDescription entityForName:@"PartsList" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:partsEntity];

    NSPredicate *predicate = [NSPredicate predicateWithFormat: @"customerTAMSID == %@ AND lineAbbreviation == %@ AND partNumber == %@", selectedCustomer.customerTAMSID, part.lineAbbrev, part.partNumber];
    [fetchRequest setPredicate:predicate];

    NSError *error = nil;
    NSArray *fetchedParts = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

    if ([fetchedParts count] == 0) {
        //Create a new instance of the entity managed object by the fetched results controller
        NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
        NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];

        NSLog(@"Entity Name: %@", [entity name]);

        NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

        //Add fields to Managed Object
        int sortOrder = [[fetchedResultsController fetchedObjects] count];
        sortOrder++;

        [newManagedObject setValue:[part lineAbbrev] forKey:@"lineAbbreviation"];
        [newManagedObject setValue:[part partNumber] forKey:@"partNumber"];
        [newManagedObject setValue:[NSNumber numberWithInt:[[part orderQty] intValue]] forKey:@"orderQuantity"];
        [newManagedObject setValue:selectedCustomer.customerTAMSID forKey:@"customerTAMSID"];
        [newManagedObject setValue:[NSNumber numberWithInt:sortOrder] forKey:@"sortOrder"];

        //Save the context
        NSError *error = nil;
        if (![context save:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }

        //reload Customer list 
        NSIndexPath *insertionPath = [fetchedResultsController indexPathForObject:newManagedObject];
        [self.partsListGrid selectRowAtIndexPath:insertionPath animated:YES scrollPosition:UITableViewScrollPositionTop];
        [self.partsListGrid reloadData];
    }
}

Это самый большой (самый серьезный) дефект, который я должен выяснить для нашего следующего выпуска (который очень скоро). Буду признателен за любую помощь! Спасибо!

Ответы [ 2 ]

2 голосов
/ 21 февраля 2011

начать с исправления утечки NSFetchedResultsCOntroller в

-(void) CustomerSelectedRaised:(NSNotification *)notif
{
    /*...*/
    fetchedResultsController = nil;
    /*...*/
}

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

1 голос
/ 21 февраля 2011

хорошо, благодаря этой ТАКОЙ нити , похоже, она у меня работает:

Я отредактировал метод CustomerSelectedRaised, чтобы он выглядел так:

-(void) CustomerSelectedRaised:(NSNotification *)notif
{
    NSLog(@"Received Notification - Customer Selected");
    selectedCustomer = (Customer *)[notif object];
    [self buildCustomerInfoText];
    if (popoverController != nil) {
        [popoverController dismissPopoverAnimated:YES];
    }
    //this is the new code
    NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
    NSEntityDescription *entity = nil;
    entity = [NSEntityDescription entityForName:@"PartsList" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"customerTAMSID == %@", selectedCustomer.customerTAMSID]]; 

    [NSFetchedResultsController deleteCacheWithName:nil];
    // end of new code

    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        //Update to handle error appropriately
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1); //fail
    }

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