NSFetchedResultsController обновляет записи UITableView без повторной загрузки - PullRequest
0 голосов
/ 07 февраля 2012

У меня есть UITableView, управляемый NSFetchedResultsController. Я вызываю метод для создания NSPredicate, который фильтрует мои объекты, которые имеют временную метку с сегодняшнего дня. И в моем NSFetchedResultsController я применяю предикат.

if (appDelegate.displayTodayOnly) {
    [fetchRequest setPredicate:datePredicate];
}

Все это прекрасно работает. Однако иногда мне нужно просматривать записи, предшествующие «сегодня». Я делаю это, проводя вниз по табличному представлению, когда оно уже находится в начале таблицы.

-(void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {  
    if (self.tableView.contentOffset.y<0) {
        if (appDelegate.displayTodayOnly) {
            [appDelegate setDisplayTodayOnly:NO];
            NSInteger resultsOffset = [[self.fetchedResultsController fetchedObjects] count];
            //[self.tableView beginUpdates];
            [__fetchedResultsController release];
            __fetchedResultsController=nil;
            NSError *error;
            if (![[self fetchedResultsController] performFetch:&error]) {
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                exit(-1);  // Fail
            }
            //[self.tableView endUpdates];
            NSInteger fullCount = [[self.fetchedResultsController fetchedObjects] count];
            if (fullCount>resultsOffset) {
                NSUInteger sect = [[self.fetchedResultsController sections] count]-2;
                id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:sect];
                NSUInteger rows = [sectionInfo numberOfObjects]-1;
                NSIndexPath *indexing = [NSIndexPath indexPathForRow:rows inSection:sect];
                NSLog(@"IndexPath = section:%d row:%d",sect,rows);
                [self.tableView reloadData];
                [self performSelector:@selector(scrollToIndexPath:) withObject:indexing afterDelay:0.0001];
            }
        }
    }
}

Это тоже работает, но не элегантно. Он отбрасывает fetchedResultsController и перезагружает таблицу, начиная с записей с начала времени, насколько это касается записей. Затем он прокручивается до пути индекса над записью предыдущей таблицы.

Я хотел бы, чтобы записи загружались и вставлялись перед вершиной текущей таблицы. Кто-нибудь знает элегантный способ изменить выборку, чтобы это произошло?

Ответы [ 2 ]

1 голос
/ 07 февраля 2012

Обычно я устанавливаю

self.fetchedResultsController = nil; 

и перезагружаюсь.Это очень эффективно и приводит к минимуму кода (при условии, что вы загружаете и создаете контроллер извлеченных результатов лениво, как в шаблонах Xcode).

0 голосов
/ 12 февраля 2012

Я публикую свое решение в надежде, что оно может помочь кому-то еще нуждающемуся.

Я все еще устанавливаю экземпляр NSFetchedResultsController на ноль и получаю новый экземпляр с другим предикатом. Затем, вместо перезагрузки таблицы (что вызвало дезориентирующий скачок), в цикле for (вручную) я вручную вызываю [self.tableView insertSections:[NSIndexSet indexSetWithIndex:i] withRowAnimation:UITableViewRowAnimationNone];, который почти напрямую выходит из шаблона controllerWillChangeContent: метода <NSFetchedResultsControllerDelegate>. Это работает, потому что последний раздел всегда будет разделом на сегодня. Если на сегодня нет записей, мне нужно перезагрузить данные, потому что будет несоответствие количества вставленных разделов, потому что сегодняшний пустой раздел считается разделом.

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{   
    if (self.tableView.contentOffset.y<0) {
        if (appDelegate.displayTodayOnly) {
            [appDelegate setTodayOnlyMemory:NO];
            NSUInteger resultsOffset = [[self.fetchedResultsController fetchedObjects] count];
           [__fetchedResultsController release];
            __fetchedResultsController = nil;
            self.fetchedResultsController = nil;

            NSError *error = nil;
            if (![self.fetchedResultsController performFetch:&error])
            {
                NSLog(@"error in fetched results controller of Memory Notes");
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
            if (resultsOffset) {
                [self.tableView beginUpdates];
                NSInteger afCount = ([[self.fetchedResultsController sections] count]-1);
                for (NSInteger i=0; i<afCount; i++) {
                    [self.tableView insertSections:[NSIndexSet indexSetWithIndex:i] withRowAnimation:UITableViewRowAnimationNone]; 
                }
                [self.tableView endUpdates];
            } else {
                [self.tableView reloadData];
            }            
            [self performSelector:@selector(scrollToSpot) withObject:nil afterDelay:0.01f];
        }
    }
}

Кроме того, вот мой метод scrollToSpot для того, чтобы оказаться в нужном месте.

-(void)scrollToSpot
{    
    NSArray *sectArray = [self.fetchedResultsController sections];
    if ([sectArray count]>1) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [sectArray objectAtIndex:([sectArray count]-2)];
        NSInteger theRow = [sectionInfo numberOfObjects]-1;
        NSIndexPath* ipath = [NSIndexPath indexPathForRow:theRow inSection:([sectArray count]-2)];
        NSLog(@"Row:%d",ipath.row);
        [self.tableView scrollToRowAtIndexPath:ipath atScrollPosition:UITableViewScrollPositionTop animated:NO];
        NSLog(@"ContentOffset:%.0f",self.tableView.contentOffset.y);
    }
}
...