限制 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 中显示数据,第二次运行正常