NSFetchedResultsControllerDelegate & UITableViewDelegate Behavior - PullRequest
0 голосов
/ 28 февраля 2011

Я столкнулся с поведением делегатов FRC и TableView, которое кажется несовместимым:

  • Первоначальный вызов executeFetch приводит к тому, что методы делегата вызываются, как и ожидалось. Однако, если я обновлю предикат для FRC baseFetch и затем снова вызову executeFetch , методы делегата FRC никогда не будут вызваны, и TableView не будет обновлен с новыми данными. Чтобы заставить таблицу обновлять и отображать новые данные, я явно вызываю reloadData .
  • Первоначальный вызов executeFetch правильно строит разделы TableView. Если я изменю FRC (новый FCR имеет другой fetchRequest и sectionNameKeyPath ) и снова вызову executeFetch , таблица и секции обновляются, чтобы соответствовать новым результатам, так как ожидается. ОДНАКО, если я затем вернусь к исходному FRC и вызову executeFetch , разделы будут иметь правильные имена, но со структурой раздела / строки предыдущего FRC. Для принудительного обновления разделов я явно вызываю reloadSectionIndexTitles .

Мне кажется, что делегаты должны стрелять каждый раз, когда мы вызываем executeFetch , если что-то меняется. Явный вызов reloadData и reloadSectionIndexTitles кажется дорогостоящим и ненужным шагом, поскольку для этого существуют делегаты. Я что-то упустил?

Вот соответствующий код:

NSFetchedResultsControllerDelegate

    - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.myTable beginUpdates];
}


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

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.myTable insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[self.myTable cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [self.myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            // Reloading the section inserts a new row and ensures that titles are updated appropriately.
            [self.myTable reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }

}


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

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.myTable insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.myTable deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.myTable endUpdates];
}

UITableViewDelegate

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.
    return [[currentFCR sections] count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[currentFCR sections] objectAtIndex:section];
    return section.name;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    id <NSFetchedResultsSectionInfo> sectionInfo = [[currentFCR sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell...
    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

1050 * Получение *

- (NSFetchedResultsController *)FRC1 {

    if (FRC1 != nil) {
        return FRC1;
    }

    NSFetchRequest *request = [[DataProvider instance] getFetch];
    [[DataProvider instance] sortListByFirstSort:request];
    [request setFetchBatchSize:20];

    FRC1 = [[NSFetchedResultsController alloc] initWithFetchRequest:request 
                                                                   managedObjectContext:[[DataProvider instance] managedObjectContext] 
                                                                     sectionNameKeyPath:@"groupName" 
                                                                              cacheName:nil];
    return FRC1;    

}

- (NSFetchedResultsController *)FRC2 {

    if (FRC2 != nil) {
        return FRC2;
    }

    NSFetchRequest *request = [[DataProvider instance] getFetch];
    [[DataProvider instance] sortListBySecondSort:request]; 


 [request setFetchBatchSize:20];

        FRC2 = [[NSFetchedResultsController alloc] initWithFetchRequest:request 
                                                       managedObjectContext:[[DataProvider instance] managedObjectContext] 
                                                         sectionNameKeyPath:@"name" 
                                                                  cacheName:nil];
        return FRC2;    

    }

    -(void)doFetch{
    NSError *error;
    if (![currentFCR performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
    [self.myTable reloadData];
    [self.myTable reloadSectionIndexTitles];
}

1 Ответ

0 голосов
/ 28 февраля 2011

NSFetchedResultsControllerDelegate методы controllerWillChangeContent: и т. Д. Вызываются только в том случае, если для экземпляра NSFetchedResultsController установлен делегат.Я не вижу ни одного делегата, установленного в вашем коде.

Начальная загрузка таблицы (или явный вызов reloadTable) приведет к вызову методов UITableViewDataSource, получающих данные из currentFCR.Методы NSFetchedResultsControllerDelegate не будут вызываться, если делегат не установлен на NSFetchedResultsController.

Кроме того, методы NSFetchedResultsControllerDelegate вызываются только в том случае, если какой-либо из соответствующих управляемых объектов изменяется (или добавляется / удаляется) в NSManagedObject.1005 *

Если вы хотите заменить объект NSFetchedResultsController, вам необходимо явно перезагрузить таблицу.

...