Получение NSFetchedResultsController, NSSortDescription и sectionNameForKeyPath для совместной работы - PullRequest
7 голосов
/ 20 марта 2011

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

Элемент << -> Категория .

В настоящее время я извлекаю Item экземпляров и отображаю их в разделах, используя элемент category.name. В этом случае я могу использовать дескриптор сортировки для сортировки категорий по имени, что довольно просто и работает нормально (соответствующий код ниже):

-(NSFetchedResultsController*)fetchedResultsController {
    if (fetchedResultsController_ != nil)
        return fetchedResultsController_;
    NSManagedObjectContext *moc = [order_ managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:moc];
    [fetchRequest setEntity:entity];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"category.name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    [sortDescriptors release];
    [sortDescriptor release];
    NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
                                          initWithFetchRequest:fetchRequest
                                          managedObjectContext:moc
                                          sectionNameKeyPath:@"category.name"
                                          cacheName:nil];
    controller.delegate = self;
    self.fetchedResultsController = controller;
    [controller release];
    [fetchRequest release];

    NSError *error = nil;
    if (![fetchedResultsController_ performFetch:&error]) {
        // Error handling
    }
    return fetchedResultsController_;
}

Моя проблема сейчас в том, что мне нужно отсортировать эти категории не по имени, а по атрибуту (NSNumber*) displayOrder, который является частью сущности Category . НО Мне нужно, чтобы заголовки разделов в табличном представлении продолжали использовать категории name.

Если я установлю sortDescriptor для использования category.displayOrder и оставлю sectionNameKeyPath равным category.name, заголовки разделов будут работать нормально, но fetDescriptor просто игнорируется fetchedResultsController, а разделы таблицы упорядочиваются по имени категории (не знаю, почему ??).

Моя следующая идея состояла в том, чтобы переписать метод получения displayOrder, но это не сильно меня задело, так как типы возвращаемых данных разные, плюс мне нужно было фактическое значение displayOrder для сортировки разделов.

Так что сейчас у меня есть решение, которое кажется немного неуклюжим (код ниже), и мне интересно, есть ли лучший способ добиться того же, используя только fetchedResultsController.

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// The code below grabs a reference to first object for a given section
// and uses it to return the associated category name
{
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    NSArray *menuItems = [sectionInfo objects];
    if ([menuItems count] > 0)
    {
        MenuItem *menuItem = [menuItems objectAtIndex:0];
        NSString *categoryName = menuItem.category.name;
        return categoryName;
    }
    return [sectionInfo name];
}

Я что-то упустил здесь?

Заранее спасибо за ваши мысли.

1037 * Рог *

Ответы [ 4 ]

1 голос
/ 01 июня 2011

Это очень хорошее решение проблемы, Рог.

Вы, конечно, не хотите / не должны иметь подкласс NSFetchedResultsController.

@ aroth, у нас недостаточно информации, чтобы узнать подробности его объектной модели, но названия определенно подразумевают, что категория не владеет элементом. Предмет имеет категорию. Его цель - показать список предметов, поэтому он выбирает предметы.

1 голос
/ 24 марта 2011

Что касается сортировки, в документации есть следующее:

Если контроллер генерирует секции, первый дескриптор сортировки в массиве используется для группировки объектовна разделы;его ключ должен совпадать с sectionNameKeyPath, или относительное упорядочение с использованием его ключа должно совпадать с использованием sectionNameKeyPath.

На английском языке (возможно, вы уже знаете этот Rog, но, опять же, вы можете не знать об этом людейкто ищет это позже, может оценить объяснение), это означает, что если вы используете разделы, то сортировка по NSFetchRequest должна сгруппировать все элементы в одном разделе вместе.Это может быть сделано из-за того, что первый критерий сортировки будет полем, используемым в качестве имени раздела, или из-за того, что первый критерий сортировки будет чем-то еще, что приведет к такой же группировке.

Документация не 'не уточняйте, что произойдет, если вы облажаетесь;возможно, он просто полностью испортит названия разделов, повторит разделы, пропустит разделы, обнаружит ситуацию и «исправит» вашу сортировку, или даже просто вылетит.Есть ли в ваших категориях одинаковый displayOrder?

Ваше решение, безусловно, работоспособно, и если вы не можете заставить его работать правильно, сортировка по displayOrder при названии разделов по category.name это, вероятно, ваше лучшее решение.

1 голос
/ 31 марта 2011

Почему вы получаете Item, а не Category? Если я правильно понимаю ваши отношения, Category владеет отношением 1 ко многим с Item, поэтому в теории экземпляр Category должен иметь свойство items, которое возвращает каждый Item в этой категории.

Если это так, то вы можете просто получить все свои категории, а затем отсортировать их по displayOrder. Затем забудьте об использовании разделов в самом NSFetchedResultsController. Вместо этого ваши связанные tableView методы будут выглядеть примерно так:

- (NSInteger)numberOfSections {
    return [[self.fetchedResultsController fetchedObjects] count];
}

- (NSInteger)numberOfRowsInSection:(NSInteger)section {
    Category* category = [[self.fetchedResultsController fetchedObjects] objectAtIndex:section];
    return [[category items] count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    Category* category = [[self.fetchedResultsController fetchedObjects] objectAtIndex:section];
    return category.name;
} 

Короче говоря, я думаю, что вы слишком усложняете ситуацию, выбирая Item вместо Category и пытаясь заставить NSFetchedResultsController управлять группировкой разделов за вас. Это намного проще и требует гораздо меньше кода, чтобы просто сделать управление секциями самостоятельно.

0 голосов
/ 21 марта 2011

Возможно, вам нужно создать подкласс NSFetchedResultsController и настроить функции имени раздела. См. Документацию класса NSFetchedResultsController по подклассам.

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