【问题标题】:Coredata fetching and grouping objects in sectionsCoredata 在部分中获取和分组对象
【发布时间】:2011-08-15 21:55:28
【问题描述】:

我正在使用一个非常复杂的对象模型,并且在将我的一些提取分解成部分以在表格视图中显示时遇到了一些麻烦。

我需要将Meeting 托管对象分组到几个不同的“口袋”中,例如项目、客户和其他几个。出于几个原因,我决定将这些实现为可以与会议实体关联的标签。

所以我创建了一个新的Tag 实体,它有一个类型和一个值,并建立了两者之间的关系:

Meeting <<-->> Tag

如果我想将会议与项目相关联,我创建一个名称为“项目”和值为“项目名称”的标签,然后通过关系将其添加到会议实体。

我最初考虑使用 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];

在这种特殊情况下,提取确实有效,但不知何故,我得到了意想不到的结果,其中不仅显示了具有值 clientTags,而且还显示了具有值 project 的结果???

如果我将谓词更改为tags.name == 'project',我会得到一个异常:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'

我可能在这里遗漏了一些基本的东西,而且我承认我在谓词方面没有很多经验,但 Apple 关于该主题的文档还有很多不足之处。

作为一个附带问题,我也不明白为什么我必须在self.tags.value 的 sectionNameKeyPath 中添加self?它有什么作用??在这种情况下,如果我不添加它,我也会抛出异常:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid to many relationship in setPropertiesToFetch: (tags.value)

最后,在这种情况下,使用 fetched results controller 的替代方法是什么?会不会是一堆获取请求,我首先获取Tag 的每个实例,其中name == 'project' 并遍历数组以提取与其关联的会议对象?这似乎效率很低,但目前我能想到的只有这些,所以如果您有任何其他想法,我很想听听。

非常感谢您抽出宝贵的时间,

罗格

【问题讨论】:

    标签: ios core-data nsfetchedresultscontroller nspredicate


    【解决方案1】:

    问题是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 对象的列表,其中tags 中的ANY 的类型为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 子类中实现它,并使您的具体子类继承自该属性。

    【讨论】:

    • 感谢@Nathan de Vries,感谢您抽出宝贵时间回答这个问题。
    【解决方案2】:

    “Apple 关于 [NSPredicate] 的文档还有很多不足之处”——完全同意!

    tags.name 无效,因为标签是一个集合,没有对象,有(比如说)三个

    我认为您想要"tags contains %@", projectTag 之类的东西,但我不确定语法。可能是"%@ IN %@", projectTag, thing.tags

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多