NSFetchedResultsController всегда не возвращает строк - PullRequest
6 голосов
/ 04 декабря 2011

Я пытаюсь заставить NSFetchedResultsController работать с моим табличным представлением, но, несмотря на все мои усилия, чтобы правильно настроить его, он всегда не возвращает строк. Я открыл свое хранилище данных через Finder и проверил через редактор SQLite, что на самом деле существует множество записей, но он всегда возвращает ноль. Чего мне не хватает?

Пользовательский геттер для контроллера:

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

    RBGameItemController* itemController = [RBGameItemController sharedInstance];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"GameItem" inManagedObjectContext:itemController.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest  
                                                                                                  managedObjectContext:itemController.managedObjectContext 
                                                                                                    sectionNameKeyPath:nil 
                                                                                                             cacheName:@"Root"];
    self.fetchedResultsController = theFetchedResultsController;
    self.fetchedResultsController.delegate = self;

    [sort release];
    [fetchRequest release];
    [theFetchedResultsController release];

    return self.fetchedResultsController;
}

Я получаю данные в viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
}

Полученный делегат результатов:

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

    NSLog(@"controllerWillChangeContent");
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    NSLog(@"controller:didChangeObject:");
    UITableView *tableView = self.tableView;

    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:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

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


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

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


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

Я реализую оба метода для раздела и номера строки, который возвращает 1 для разделов и 0 для строк:

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
    int sections = [[self.fetchedResultsController sections] count];
    NSLog(@"sections=%i", sections);
     return sections;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    int rows = [sectionInfo numberOfObjects];

    NSLog(@"rows=%i", rows);

    return rows;
}

Ответы [ 3 ]

11 голосов
/ 04 декабря 2011

Вы пытались вручную выполнить запрос с запросом на выборку, чтобы убедиться, что он возвращает то, что вы ожидаете?В своем обычном fetchedResultsController попробуйте выполнить:

NSArray *entities = [itemController.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(@"%d",entities.count);

и посмотрите, что получится.

Также попробуйте настроить fetchedRequestController без кэша.Возможно, вы повторно используете тот же кеш по имени в других частях приложения?

5 голосов
/ 22 июля 2013

Назначение делегату:

 self.fetchedResultsController.delegate = self;

Последняя строка:

return self.fetchedResultsController;

Это приведет к циклическому вызову этого метода.Не пишите код, подобный этому.

Критическими точками в этом вызове являются managedObjectContext, sortDescriptor и сущность.Поэтому убедитесь, что ни один из них не равен нулю, и что значения соответствуют вашим ожиданиям.

static NSString *const NSString *kMyFetchedResultsControllerCacheName = @"RootCache";



- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController == nil) {
        [NSFetchedResultsController deleteCacheWithName:];
        RBGameItemController* itemController = [RBGameItemController sharedInstance];

        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([GameItem class]) inManagedObjectContext:itemController.managedObjectContext];
        [fetchRequest setEntity:entity];

        NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
        [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

        [fetchRequest setFetchBatchSize:20];

        NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:itemController.managedObjectContext sectionNameKeyPath:nil cacheName:kMyFetchedResultsControllerCacheName];
        self.fetchedResultsController = fetchedResultsController;
        fetchedResultsController.delegate = self;
    }

    return _fetchedResultsController;
}

Наконец, вам всегда нужно убедиться, что executeFetch вызывается, вероятно, в viewDidLoad:

NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
if (error != nil) {
    NSLog(@"%@", error.localizedDescription);
}
0 голосов
/ 26 апреля 2013

передача nil для cacheName также решила проблему для меня ... пока не знаю, почему.

...