有没有比获取请求更快的方法来检索 Core Data 中的特定托管对象?

Posted

技术标签:

【中文标题】有没有比获取请求更快的方法来检索 Core Data 中的特定托管对象?【英文标题】:Is there a faster way to retrieve a specific managedObject in Core Data than a fetch request? 【发布时间】:2013-12-19 19:31:01 【问题描述】:

我有一个方法来创建每个具有三个属性的托管对象 (IntersectionObject)。这三个属性本身就是托管对象。

PropertyObject1、PropertyObject2 和 PropertyObject3 各有大约 20 种不同的可能性。

IntersectionObject 本质上是特定 PropertyObject1、PropertyObject2 和 PropertyObject3 的组合。

大约有 1200 个 IntersectionObjects,为了创建它们,我使用获取请求来检索和设置正确的 PropertyObject:

- (PropertyObject1 *)fetchedPropertyObject1FromID: (NSNumber *)propertyObjectID 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"PropertyObject1"  inManagedObjectContext:[self managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSError *error = nil;
    NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil) 
        NSLog(@"error fetching PropertyObject from ID, error:%@", error);
    return nil;
    

    for (PropertyObject1 *object in fetchedObjects) 

        if (object.propertyObjectID.longValue == propertyObjectID.longValue) 
        return object;
        
    

    return nil;


我发现为 1200 个 IntersectionObjects 中的每一个重复此提取 3 次大约需要 2 秒,而且太慢了。有没有更快的方法来做到这一点?

编辑:接受的答案有我在它下面的 cmets 中使用的解决方案。事实证明,简单地将 PropertyObjects 映射到字典是获取关联对象的最简单、最快捷的方法。

【问题讨论】:

我不建议在NSManagedObjectID 上致电longValue。将其视为使用的对象要好得多-isEqual: 这里的 ID 不是 NSManagedObjectID 而是来自 JSON 数据的任意 ID(我相信它是一个 NSNumber),但我相信您的建议仍然适用,感谢您指出。 在上面的代码中,它是来自NSManagedObject-objectID。希望您没有在 NSManagedObject 子类中覆盖 -objectID 是的,好点! ID 在我的代码中有不同的名称,我只是想通过使用 objectID 使其更通用,而没有意识到这已经被采用了。我将在上面的代码中更改它以澄清。 【参考方案1】:

如果您有托管对象 ID,请在 MOC 上使用 objectWithID:

如果您不这样做,并且您将在短时间内创建大量关联,请分批从 MOC 获取所有托管对象(可能每批 100 个项目,请参阅fetchBatchSizeNSFetchRequest)上,创建一个字典,将您的objectID 映射到托管对象,这样您就可以进行本地查找。使用refreshObject:mergeChanges: 处理批处理时,将每个对象重新变为故障。

【讨论】:

我以前没有使用过 managedObjectIDs,但是从我一直在阅读的关于它们的内容来看,我需要先 saveContext 才能使用它们的永久 ID。然后我的问题是:每次创建新的 PropetyObject 并将 moID 分配为它的属性时,是否需要保存上下文? 我已经编辑了答案,因为我最初的建议并不容易实现。对象确实会获得临时 ID,但如果您正在使用它们,您会想要保存它们。 如果您只是不经常进行这些关联,那么@RyanG 的答案是一个不错的选择。 此关联仅用于设置 1200 个对象。我可以简单地使用 tempID,然后在完成后使用 saveContext 吗? 如果您同时创建所有对象,只需在此处创建一个映射字典即可。无需进行任何获取或托管对象 ID 查找...【参考方案2】:

使用谓词来执行此操作,还将获取限制设置为 1。这应该会以更优化的方式获得您的结果:

- (PropertyObject1 *)fetchedPropertyObject1FromID: (NSNumber *)objectID 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"PropertyObject1"  inManagedObjectContext:[self managedObjectContext]];
    [fetchRequest setEntity:entity];

    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"objectID == %@", objectID]];
    [fetchRequest setFetchLimit:1];


    NSError *error = nil;
    NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil) 
        NSLog(@"error fetching PropertyObject from ID, error:%@", error);
    return nil;
    

    if(fetchedObjects.count > 0)
    
        [return fetchedObjects objectAtIndex:0];
    
    return nil;


【讨论】:

我刚刚尝试了这种方法来与我最初的尝试进行比较:WITH 谓词:2.9 秒,没有谓词(原始方法):1.8 秒。不知道为什么... 添加谓词会导致字符串解析(predicateWithFormat)加上它对objectID进行字符串比较。这就是它更贵的原因。

以上是关于有没有比获取请求更快的方法来检索 Core Data 中的特定托管对象?的主要内容,如果未能解决你的问题,请参考以下文章

有没有更快的方法来检索 System.Environment.UserName?

比 O(n) 更快地获取数组元素的索引

有没有比 fread() 更快的方法来读取大数据?

有没有更快的方法来检查 LINQ to XML 中的 XML 元素?

有没有比这更快的方法来查找目录和所有子目录中的所有文件?

有没有比使用 np.where 更快的方法来迭代一个非常大的 2D numpy 数组?