使用具有m:n关系的NSFetchedResultsController

时间:2012-11-13 18:52:18

标签: objective-c core-data nsfetchedresultscontroller

我的模型看起来像这样:

enter image description here

在代码中,我强制执行虽然A可以有多个B,但每个C只有一个B。

我想要做的是列出给定C的所有As,按B分组。现在,如果我从我的C开始,得到所有B的集合,然后得到一组,那么这是相当简单的。所有对于每个B.

我想要做的是列出使用NSFetchedResultsController。我可以使用“ANY b.c MATCHES myC”来过滤它们,但是我看不出怎么做就是用正确的B对它们进行分组。

换句话说,由于A有很多B,我如何找出属于我的C的那个,并在NSFetchedResultsController中使用它?这甚至可能吗?

1 个答案:

答案 0 :(得分:1)

廉价的黑客攻击方法:

向对象nameOfRelevantB添加一个名为A的类别方法,将myC设置为全局(或者,可能将其传递给A上的类方法,将其存储到a文件本地静态)然后将nameOfRelevantB设置为sectionNameKeyPath上的NSFetchedResultsController

nameOfRelevantB会找到与提供的C匹配的B并返回它。

明显的缺点是你一次只能减少一个相关的C.

您可以通过在您的应用程序中获取结果控制器与队列或线程具有一对一关系并将相关C存储为队列或线程上下文的规则来改善这一点,但是您需要编写手册无论如何UITableViewDataSource以便将结果移回主队列/线程。

如果您打算编写一个自定义数据源,您可以将其设为NSFetchedResultsControllerDelegate,将其分解为自己的意愿部分,避免[file static] global。

更彻底的解决方案:

您可以覆盖valueForUndefinedKey:子类上的NSManagedObject,并将相关的C objectID直接放入密钥路径中。这显然是安全的,因为托管对象ID具有URIRepresentationNSURL提供absoluteString。然后,每个A可以从密钥路径获取字符串URI,询问其上下文的持久性存储协调器managedObjectIDForURIRepresentation,然后询问上下文existingObjectWithID:error:以获取相关的C.一旦它具有C它可以从适当的B中返回标题。

如果没有任何类型的全球状态,那就能实现你想要的目标。您还将直接使用NSFetchedResultsController,为其提供一个可以确定部分的关键路径。

所以,例如(直接输入,未经测试)

// get a URI for the relevant myC and prefix it with an '@'
// so that it's definitely clearly not an ordinary property
fetchedResults.sectionNameKeyPath = 
        [NSString stringWithFormat:@"@%@", 
              [[myC.objectID URIRepresentation] absoluteString]];

... in your subclass for A ...

- (id)valueForUndefinedKey:(NSString *)key
{
    // check that the key begins with the magic '@' symbol
    if(![key length] || [key characterAtIndex:0] != '@')
        return [super valueForUndefinedKey:key];

    // get the original URL
    NSString *URLString = [key substringFromIndex:1];
    NSURL *URL = [NSURL URLWithString:URLString];

    // transform the URL into the relevant instance of C
    NSManagedObjectID *objectID = [self.context.persistentStoreCoordinator
                  managedObjectIDForURIRepresentation:URL];
    NSError *error = nil;
    MyCClass *myC = [self.context existingObjectWithID:objectID error:&error];

    // check that we got an appropriate instance and didn't
    // generate an error
    if(!myC || error) return [super valueForUndefinedKey:key];

    /*
        code here to find the appropriate B and return a suitable title
    */
}

主要的警告是,对象ID以及URI可能会在对象的初始创建和第一次保存之间发生变化。如果您已经保存了上下文,只要对象在商店中,对象ID就会保持不变。