NSFetchedResultsController创建了太多部分

时间:2014-08-08 12:02:45

标签: ios objective-c uitableview core-data nsfetchedresultscontroller

我复制了NSFetchedResultsController的申请documentation中的代码。 如果我想将结果分配给显示结果的UITableView,则表示应该提供sectionNameKeyPath

我的目标是根据模型对象名称开头的字符对结果进行分区。即按名称排序。

此代码完全按照名称排序(但按名称排序),但不是对行组进行分区,而是每行都显示在各自的部分中。 (节的数量基本上等于行数。)

我相信我在某个地方犯了一个愚蠢的错误,但我现在花了两个半小时,我看不到任何东西。我只是要粘贴UITableView的委托/数据源方法,我将提供数据。

#pragma mark NSFetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [Place MR_requestAllSortedBy:@"name" ascending:YES];
    [fetchRequest setFetchLimit:0];
    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[NSManagedObjectContext MR_contextForCurrentThread] sectionNameKeyPath:@"name" cacheName:@"places"];
    _fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;
    return _fetchedResultsController;
}


#pragma mark UITableViewDelegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:listTableViewCellIdentifier];

    Place *place = [_fetchedResultsController objectAtIndexPath:indexPath];

    FAKIcon *categoryIcon = [FFPlaceHandler getIconForPlaceWithCategoryID:place.main_category andSize:CELL_ICON_SIZE];
    [categoryIcon addAttribute:NSForegroundColorAttributeName value:FF_WHITE_COLOR];

    FAKIcon *circleIcon = [FAKFontAwesome circleIconWithSize:CELL_ICON_CIRCLE_SIZE];
    [circleIcon addAttribute:NSForegroundColorAttributeName value:[FFPlaceHandler getColorForPlaceWithCategoryID:place.main_category]];

    cell.image.image = [UIImage imageWithStackedIcons:@[circleIcon, categoryIcon] imageSize:CGSizeMake(CELL_ICON_CIRCLE_SIZE, CELL_ICON_CIRCLE_SIZE)];

    cell.title.text = place.name;
    cell.addressLabel.text = place.place_contact_info.address;

    [cell setDistanceWithDistance:[place.distance_from_user floatValue]];

    cell.indexPath = indexPath;
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    return cell;
}

#pragma mark UITableViewDatasource

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if ([[_fetchedResultsController sections] count] > 1) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo name];
    } else
        return nil;
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return [_fetchedResultsController sectionIndexTitles];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
    return [_fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}


- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40.0;
}

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
    if ([[_fetchedResultsController sections] count] > 1) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo numberOfObjects] ;
    } else
        return 0;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [[_fetchedResultsController sections] count];
}

为什么UITableViewCell分配了一个部分,而不是按字母顺序划分?

编辑:

通过在核心数据中的place表中添加一个字段来解决它。此字段包含每个记录的第一个字符。在此之后,我改变了我的sectionKeyPath,如此方法所示:

#pragma mark NSFetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [Place MR_requestAllSortedBy:@"name" ascending:YES];
    [fetchRequest setFetchLimit:0];
    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[NSManagedObjectContext MR_contextForCurrentThread] sectionNameKeyPath:@"name_first_character" cacheName:@"places"];
    _fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;
    return _fetchedResultsController;
}

此外,我根据 moby 的建议,将> 1替换为> 0! 我现在有一些相当不错的部分:)

2 个答案:

答案 0 :(得分:1)

按键路径name进行切片将为每个具有不同名称值的模型创建一个新部分。因此,如果您有20个模型并且它们都具有不同的name值,则您将有20个部分。如果您有20个模型,其中10个拥有name A ,其中10个拥有name B ,则您将拥有2个部分。< / p>

另外,在你的

 - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {

你正在检查

if ([[_fetchedResultsController sections] count] > 1) 

相反,我认为你应该检查count > 0而不是1。

答案 1 :(得分:1)

一般情况下,如果您使用外部SDK /框架(如魔法记录),我建议您在问题中提及此内容。

另外值得一提的是,要明确......

表视图数据源方法是;

  • cellForRowAtIndexPath
  • numberOfRowsInSection
  • numberOfSectionsInTableView
  • titleForHeaderInSection
  • sectionIndexTitlesForTableView
  • sectionForSectionIndexTitle

表视图委托方法是;

  • heightForHeaderInSection

如果你使用魔法记录,你可以为你的FRC指定一个与你的sectionNameKeyPath相同的主要(第一)排序描述符......

例如......

NSSortDescriptor *sortDescriptorPrimary = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
NSSortDescriptor *sortDescriptorSecondary = [NSSortDescriptor sortDescriptorWithKey:<<other attribute>> ascending:YES];

然后设置你的获取请求排序描述符......

[fetchRequest setSortDescriptor:[NSArray arrayWithObjects: sortDescriptorPrimary, sortDescriptorSecondary, nil]];

通过这种方式,您的FRC将以与您的部分相同的顺序将数据提供给表格视图,然后按照您的辅助(或其他)排序描述符进行排序。

也许我已经解决了你的问题...

您正在使用魔法记录排序描述符和sectionNameKeyPath的{​​{1}}。

您需要使用每个@"name"的第一个字母。

所以,如果不考虑太多,你可以选择一个......

  1. 记录每个@"name"属性的第一个字母,并将其用作主要排序描述符和节名称关键路径,或者
  2. 您可以动态评估每个@"name"属性的第一个字母,并将其用作主要排序描述符和节名称关键路径。

    例如......

    @"name"

    但是我相信(但我不确定)这不会起作用,因为在表视图调用数据源和委托方法之前,FRC可能需要必要的数据。

    希望这有助于。