我正在处理一个非常复杂的对象模型,并且在将部分内容分解为多个部分以显示在tableview中时遇到了一些麻烦。
我需要将Meeting
托管对象分组到几个不同的“口袋”中,例如项目,客户端和其他一些。出于几个原因,我决定将这些实现为可以与会议实体关联的标签。
所以我创建了一个新的Tag
实体,它有一个类型和一个值,并建立了两者之间的关系:
Meeting <<-->> Tag
如果我想将会议与项目关联,我创建一个名为'project'的标签,并将值'Project Name',然后通过关系将其添加到会议实体。
我最初想过使用NSFetchedResultsController,但是我遇到了各种各样的问题,而这些问题我并不是很理解。
例如,这个获取(我省略了不必要的位):
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Meeting entityName] inManagedObjectContext:moc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"tags.name contains[] 'client'"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetch setEntity:entity];
[fetch setPredicate:predicate];
[fetch setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch
managedObjectContext:moc
sectionNameKeyPath:@"self.tags.value"
cacheName:nil];
在这种特殊情况下,fetch确实有效,但不知怎的,我得到了意想不到的结果,不仅Tags
带有值client
,还有值project
???
如果我将谓词更改为tags.name == 'project'
,我会收到例外:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'
我可能在这里遗漏了一些基本的东西,不可否认,我对谓词没有很多经验,但Apple关于这个主题的文档还有很多不足之处。
作为一个侧面问题和我不明白的问题,为什么我必须将self
添加到self.tags.value
中的sectionNameKeyPath?它有什么作用??在这种情况下,如果我不添加它,我也会抛出异常:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid to many relationship in setPropertiesToFetch: (tags.value)
最后,在这种情况下,使用fetched results controller的替代方法是什么?它是一堆获取请求,我首先获取Tag
的每个实例name == 'project'
并迭代数组以拉出与之关联的Meeting对象?这看起来非常低效,但我现在只能想到所以如果你有任何其他的想法,我很有兴趣听到它们。
非常感谢你的时间,
罗格
答案 0 :(得分:3)
问题是Meeting
有多个tags
,因此您需要使用汇总操作:
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Meeting entityName] inManagedObjectContext:moc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY tags.name contains[cd] 'client'"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetch setEntity:entity];
[fetch setPredicate:predicate];
[fetch setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch
managedObjectContext:moc
sectionNameKeyPath:@"clientName"
cacheName:nil];
即。向我提供Meeting
ANY
个tags
client
个clientName
类型clientName
对象的列表,并按- (NSString *)clientName {
[self willAccessValueForKey:@"clientName"];
// Set clientName to the value of the first tag with name 'client'
NSString* clientName = @"...";
[self didAccessValueForKey:@"clientName"];
return clientName;
}
对其进行分组。要使NSManagedObject
密钥路径起作用,您需要实现瞬态属性:
clientName
如果你的NSManagedObject
个子类的数量需要{{1}}属性,你可以在一个公共的抽象{{1}}子类中实现它,并使你的具体子类继承它。
答案 1 :(得分:1)
“Apple关于[NSPredicate]的文档还有很多不足之处” - 完全同意!
tags.name
无效,因为标签是一个集合,没有对象,有(比方说)其中三个
我认为你想要像"tags contains %@", projectTag
这样的东西,但我不确定语法。可能是"%@ IN %@", projectTag, thing.tags