有没有比获取请求更快的方法来检索 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 个项目,请参阅fetchBatchSize
在NSFetchRequest
)上,创建一个字典,将您的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?