在NSFetchRequest中使用NSDictionaryResultsType的NSFetchedResultsController

我一直在查看这个问题,因为一周没有任何解决方案,所以我想让问题更加概括,可能会帮助用户调查并给我一个解决方案 .

场景:

我有跟踪iOS应用程序的费用,我有一个名为“DashBoardViewController”的视图控制器(表视图控制器 - 带FRC),它基本上将我的费用/收入分类给定的一周,一个月或一年,并将其显示为部分 Headers 例如:(2012年10月1日至10月7日),它显示了根据特定周或月或年的费用/收入ROWS和相关资料 .

我的问题:

我想要完成的是:

根据“Money”实体的“Category”属性显示Distinct Results,并根据属性计算“Sum” .

但是,我的名为“仪表板视图控制器”的视图控制器填充了NSFetchedResultsController,其中部分名称键路径为“类型”,可以是费用或收入 . 为了获得不同的结果,我将在我的获取请求中使用Result类型作为NSDictionaryResultsType,这将给我独特的结果但FRC失败,它不能用于此 . 那么,我如何得到我的部分名称呢?我已经发布了以下代码 .

编辑 - 基于马丁的建议

- (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];

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

    NSPredicate *predicateDate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
    [fetchRequest setPredicate:predicateDate];


    // Edit the sort key as appropriate.

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

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

    if(self.choiceSegmentedControl.selectedIndex == 0)
    {
        choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"cat" ascending:NO];
    }

    if(self.choiceSegmentedControl.selectedIndex == 1)
    {
        choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"vendor" ascending:NO];
    }

    if(self.choiceSegmentedControl.selectedIndex == 2)
    {        
        choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"paidBy" ascending:NO];
    }

    NSArray * descriptors = [NSArray arrayWithObjects:typeSortDescriptor, dateSortDescriptor,choiceSortDescriptor, nil];

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

    NSError * anyError = nil;

    NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:
                                  [entity.propertiesByName objectForKey:@"cat"],
                                  nil];

    [fetchRequest setReturnsDistinctResults:YES];
    [fetchRequest setResultType:NSDictionaryResultType];
    [fetchRequest setPropertiesToFetch:propertiesToFetch];

    NSArray * objects = [context executeFetchRequest:fetchRequest error:&anyError];

    for (NSDictionary *d in objects)
    {
        NSLog(@"NSDictionary = %@", d);
    }

    NSSet *uniqueSet = [NSSet setWithArray:[objects valueForKey:@"cat"]];

    uniqueArray = [NSMutableArray arrayWithArray:[uniqueSet allObjects]];

    self.categoryArray = uniqueArray;

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

    }

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"type" cacheName:nil];

    //self.fetchedResultsController.delegate = self; in order to stop "change tracking"

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

    [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];

    self.startDate = startDate;
    self.endDate = endDate;


}

使用此代码,SECTION NAME KEY PATH不起作用,并且它抱怨该对象将被放置在未命名的部分中 .

回答(1)

2 years ago

获取的结果控制器不支持更改跟踪(即设置FRC委托)以及带有 NSDictionaryResultType 的获取请求 .

使用 setIncludesPendingChanges: 函数记录了原因:

特殊注意事项结果类型NSDictionaryResultType不支持值YES,包括计算聚合结果(例如max和min) . 对于字典,从fetch返回的数组反映了持久性存储中的当前状态,并未考虑上下文中的任何挂起的更改,插入或删除 .

对于获取请求,FRC的更改跟踪意味着 includesPendingChanges = YES ,这对 NSDictionaryResultType 不起作用 .

一种解决方法可能是使用没有更改跟踪的FRC,因此您不需要设置FRC委托 . 但这意味着要更新表格视图,您必须这样做

  • 保存托管对象上下文,和

  • 在FRC上调用 performFetch ,在表视图上调用 reloadData .

另一种解决方法可能是使用FRC来获取所有部分和行而不进行总和聚合,并使用结果来计算内存中聚合的新表行(例如,在 controllerDidChangeContent 中) .

UPDATE: (从讨论中)另一个重要的一点是,如果使用带有 NSDictionaryResultType 的获取请求,则获取结果控制器的 sectionNameKeyPath 必须包含在获取请求的 propertiesToFetch 中 .