限制 UITableView 行中显示的核心数据实体

Posted

技术标签:

【中文标题】限制 UITableView 行中显示的核心数据实体【英文标题】:Limit Core Data Entities Shown In UITableView row 【发布时间】:2014-04-19 04:13:29 【问题描述】:

我想我只是在这里遗漏了一些明显的东西,但这是让我不知所措的令人沮丧的事情之一。

我有一个名为 ProjectEntry 的核心数据实体。 ProjectEntry 对象显示在 uitableviews 中,使用各种属性,按日期排列(属性包括“dateAsNSDate”[NSDate]、“month”[NSString]、“year”[NSString]、“dayOfWeek”[NSString])。

我正在使用 NSFetchedResultsController 来填充表格视图。

当我最初创建和保存 ProjectEntry 对象时,“dateAsNSDate”属性被解析并转换为各种 NSString。一个字符串,也是一个属性,称为“concatMonthAndYear”。它需要“月”和“年”字符串并加入它们。所以我得到诸如“2014 年 1 月”、“2015 年 2 月”之类的东西。

我使用“concatMonthAndYear”作为我的 cell.textLabel.text 字符串以显示在我的 tableview 单元格中。

我使用 NSDate 属性对 tableview 行进行排序 (sortDescriptor),并使用 "year" 属性作为我的节标题 (sectionNameKeyPath)。

所以现在,我有一个名为“2014”的 tableview 部分,每个 tableview 行代表一个 Core Data 对象,在所述部分中命名为“2014 年 1 月”、2014 年 2 月等。

我可以点击其中一行,转到另一个 tableview,并列出 2014 年 1 月创建的所有对象,例如,通过在第二个 tableview 上使用 NSPredicate。

但是,在我的第一个 tableview 中,创建的每个 Core Data 对象都由它自己的 tableview 行表示。所以我会得到多行阅读“2014 年 1 月”或“2015 年 5 月”或其他任何内容。它们是有效的保存对象,我想要它们,但如果“concatMonthAndYear”已经存在,我想阻止创建新行。如果标题为“2014 年 1 月”的行已经存在,我不希望创建新行。我希望存储新的 Core Data 对象,而不是代表它的新 tableviewrow。例如,我只需要一行带有“2014 年 1 月”的行,就可以进入一个列出 2014 年 1 月以来所有实体的表格。

我知道如何使用 NSPredicate 将 2014 年 1 月的所有对象放入第二个表中,但是如何将 JUST ONE 对象放入第一个表中?

NSPredicate 不适合这种情况吗?我应该以某种方式阻止在 UITableView 委托方法中创建新单元格吗?每个 tableview 行都应该是唯一的,我一直在纠结是应该使用 NSFetchedResults 控制器还是在 tableview 委托方法中处理它?

还是其他方式?

有人能指出正确的方向吗?

已编辑以包含代码:

- (void)setupFetchedResultsController

    // 1 - Decide which Entity
    NSString *entityName = @"ProjectEntry";
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName);

    // 2 - Request Entity
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];

[request setReturnsDistinctResults:YES];
[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:@[@"monthYearTableSecHeader", @"year"]];

    // 3 - Filter it
    //request.predicate = [NSPredicate predicateWithFormat:@" "];

    // 4 - Sort it
    request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"year"
                                                                                                 ascending:NO],
                                                         [NSSortDescriptor sortDescriptorWithKey:@"dateAsNSDate"
                                                                                                                                             ascending:YES
                                                                                       selector:@selector(localizedCaseInsensitiveCompare:)], nil];


    //5 - Fetch
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                        managedObjectContext:self.managedObjectContext
                                                                          sectionNameKeyPath:@"year"
                                                                                   cacheName:nil];

    [self performFetch];


【问题讨论】:

您是否考虑过使用诸如distinctUnionOfObjects 之类的KVC 集合运算符进行过滤? 没有。老实说,直到你发表评论,我才知道这样的事情。我开始阅读它,但不确定如何将它应用于上述代码中的谓词。同样,我可能错过了明显的...... 如果你设置propertiesToGroupBy,你也可以使用havePredicate来做一个post-fetch filter。同样,这仅适用于您使用NSDictionaryResultType 【参考方案1】:

你可以使用

[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:@[@"concatMonthAndYear", @"year"]];

这将导致获取请求返回与“January 2014”等对象相对应的不同字典对象。

但是,您不能使用获取请求控制器的委托方法(以了解数据的更新)。

如果您需要听到更新,我建议您为您的数据添加一个间接层,其中MonthEntry 是一个代表每年月份的对象,并且与您的正常实体ProjectEntry 具有一对多的关系。这样,您可以将获取请求实体设置为MonthEntry

【讨论】:

这看起来很有趣。我要测试一下。我会尽快将其标记为“已解决”。 我建议的代码可以添加到获取请求的构造中。 正如我在回答中所说,如果您设置了获取结果控制器的委托,则不能使用字典返回类型。如果您需要跟踪更改,则需要使用不同的实体。 对。你给我指出了正确的方向。我非常感谢它,并将修改项目以包含第二个实体。 这是更好的选择。请记住,当您创建新的ProjectEntry 对象时,您必须将它们连接到新类型的对象(或创建一个然后连接)。

以上是关于限制 UITableView 行中显示的核心数据实体的主要内容,如果未能解决你的问题,请参考以下文章

需要帮助在 Swift 的 UITableView 中显示核心数据

核心数据,第一次运行不会在 uitableview 中显示数据,第二次运行正常

从核心数据中显示空的 UITableView 行

PostgreSQL 中的分组限制:显示每个组的前 N ​​行,但仅当这些行中的第一行等于特定数据时

核心数据父子UITableView关系

核心数据、UITableView 和 UISegmentedControl