带有部分名称的 NSFetchedResultsController

Posted

技术标签:

【中文标题】带有部分名称的 NSFetchedResultsController【英文标题】:NSFetchedResultsController with section names 【发布时间】:2012-11-09 04:20:17 【问题描述】:

场景:

我有一个费用跟踪 ios 应用程序,我将费用从费用详细视图控制器存储到表视图(带有获取的结果控制器)中,该表视图显示费用列表以及类别、金额和日期。我的实体“Money”中确实有一个日期属性,它是支出或收入的父实体。

我的问题:

我想要的基本上是对给定一周、一个月或一年的支出/收入进行分类,并将其显示为部分标题标题,例如:(2012 年 10 月 1 日至 10 月 7 日)并显示支出/收入根据该特定周的金额和相关内容。该视图中提供了两个按钮,如果我按下右侧按钮,它将一周增加一周(2012 年 10 月 1 日至 10 月 7 日现在显示 2012 年 10 月 8 日至 10 月 15 日),同样,左侧按钮将减少一周一个星期。我在视图中也有两个段控件。我想要做的是按下显示“每周”的段控制,如果我按下另一个显示“类别”的段 - 我将如何根据类别过滤掉我每周的费用/收入?

我想在我的表格视图中显示两个部分(一个显示支出日期,另一个显示格式的收入日期(2012 年 10 月 1 日 - 2012 年 10 月 7 日))。我将如何实现这一目标?我已经写了一些伪代码,如果有人能告诉我如何完成上述操作,那就太好了。

编辑 - 获取控制器

- (void)userDidSelectStartDate:(NSDate *)startDate andEndDate:(NSDate *)endDate
    
    AppDelegate * applicationDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext * context = [applicationDelegate managedObjectContext];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Money" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];

    [NSFetchedResultsController deleteCacheWithName:nil];

    //Here you create the predicate that filters the results to only show the ones with the selected date
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
    [fetchRequest setPredicate:predicate];

    // Set the batch size to a suitable number.
     [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.

    NSSortDescriptor * sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"type" ascending:YES];

    NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES];

    NSSortDescriptor *sortDescriptor3 = [[NSSortDescriptor alloc] initWithKey:@"cat" ascending:YES];

    NSArray * descriptors = [NSArray arrayWithObjects:sortDescriptor1, sortDescriptor2, sortDescriptor3, nil];

    [fetchRequest setSortDescriptors:descriptors];
    [fetchRequest setIncludesSubentities:YES];
    [fetchRequest setResultType:NSManagedObjectResultType];

    if(_fetchedResultsController)
    
          [_fetchedResultsController release]; _fetchedResultsController = nil;

    
    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"type" cacheName:nil];

    _fetchedResultsController.delegate = self;

    NSError *anyError = nil;

    if(![_fetchedResultsController performFetch:&anyError])
    
        NSLog(@"error fetching:%@", anyError);
    

    [sortDescriptor1 release];
    [sortDescriptor2 release];
    [sortDescriptor3 release];

    [fetchRequest release];

     //Finally you tell the tableView to reload it's data, it will then ask your NEW FRC for the new data
    [self.dashBoardTblView reloadData];


编辑 - 获取控制器委托方法

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller

     [self.dashBoardTblView beginUpdates];




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

   switch(type) 
    case NSFetchedResultsChangeInsert:
        [self.dashBoardTblView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                      withRowAnimation:UITableViewRowAnimationFade];
        break;

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


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

    switch(type) 
    case NSFetchedResultsChangeInsert:

        [self.dashBoardTblView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:

        [self.dashBoardTblView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeMove:

        [self.dashBoardTblView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
        [self.dashBoardTblView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                         withRowAnimation:UITableViewRowAnimationFade];


        break;

    case NSFetchedResultsChangeUpdate:
    
        [self.dashBoardTblView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
    
  


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

    [self.dashBoardTblView endUpdates];
 

【问题讨论】:

【参考方案1】:

要将“费用”/“收入”对象分组到不同的部分,您需要将type 属性添加到Money 实体,例如Integer 属性,即0 用于费用和@ 987654325@收入。

要按类型(费用/收入)对表格视图部分进行排序,请使用type 作为first 排序描述符:

NSSortDescriptor *s1 = [[NSSortDescriptor alloc] initWithKey:@"type" ascending:YES];

要按日期对每个部分中的条目进行排序,请使用 date 作为 second 排序描述符:

NSSortDescriptor *s2 = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES];

NSArray *descriptors = [NSArray arrayWithObjects:s1, s2, nil];
[fetchRequest setSortDescriptors:descriptors];

最后,要将表格视图按类别分组,请将type 用作sectionNameKeyPath

NSFetchedResultsController *aFetchedResultsController =
   [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                       managedObjectContext:context
                                         sectionNameKeyPath:type
                                                  cacheName:nil];

这应该给出 2 个部分,第一部分包含所有费用,第二部分包含所有收入。

现在对于部分标题,您必须实现tableView:viewForHeaderInSection:(我希望我做对了):

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    Money *money = [[sectionInfo objects] objectAtIndex:0]; // The first object in this section
    NSNumber *type = money.type;
    if (type.intValue == 0) 
        // Create and return header view for "expense" section.

     else 
        // Create and return header view for "incomes" section.

    

【讨论】:

谢谢,但我希望我的部分名称显示当前周(日期),并且行将显示类别名称。 @AngadManchanda:那我没有正确理解你的问题。你说你想要两个部分(一个用于支出,一个用于收入)。 - 也许你可以展示一个表格应该是什么样子的例子。 正是我想要两个部分。一个带有红色的部分有一个本周的标题(日期如 2012 年 10 月 1 日 - 2012 年 10 月 7 日 - 这是部分标题),行将是类别并显示费用金额。同样,另一个绿色部分显示当前周作为部分标题,行显示收入金额的类别。属性“cat”位于“Money”实体中,该实体是“Expense”和“Income”实体的父实体。现在,清楚了吗?你能帮忙吗? @AngadManchanda:好的。但是您需要“金钱”实体中的一些属性,例如 0 用于支出,1 用于收入。否则获取请求不能按类型分组。 请参阅我发布的示例屏幕截图。我将如何做到这一点?

以上是关于带有部分名称的 NSFetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章

在同一个 UITableView 的不同部分显示多个 NSFetchedResultsController

如何在带有部分的 TableView 上创建 SearchBar?

Mailchimp 可重复部分名称

更改 QHeaderView 中的部分名称

带有实例名称和域的 JDBC 连接字符串

多部分请求 - 带有 UIImage 的可编码结构