这是一个已知的错误(保存新对象时嵌套上下文没有获得永久 ID)可能,并且应该在即将发布的版本中修复......
虽然您应该能够要求永久 ID,但您应该只在已插入的对象上要求它们。
[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:0];
但是,您必须在保存 MOC 之前执行此操作,因为如果您在没有获得永久 ID 的情况下保存,临时 ID 会传播到父上下文。例如,在您保存到 mainMoc,然后获取 IDS 的情况下,backgroundMOC 仍然具有临时 ID,因此将来从中保存将创建重复数据。
请注意,获取永久 ID 一直到数据库,但如果您在主 MOC 的子 MOC 中执行此操作,则在发生这种情况时您根本不应该阻塞主线程。
所以,在你从最低级别的 MOC 中保存时,你应该有效地拥有这样的东西(当然,有适当的错误处理)......
[backgroundMoc performBlock:^{
[backgroundMoc obtainPermanentIDsForObjects:backgroundMoc.insertedObjects.allObjects error:0];
[backgroundMoc save:0];
[mainMoc performBlock:^{
[mainMoc save:0];
[masterMoc performBlock:^{
[masterMoc save:0];
}];
}];
}];
如果您愿意,还可以玩一些其他游戏。
在 NSManagedObject 上提供与此类似的类别...
@implementation NSManagedObject (initWithPermanentID)
- (id)initWithEntity:(NSEntityDescription *)entity insertWithPermanentIDIntoManagedObjectContext:(NSManagedObjectContext *)context {
if (self = [self initWithEntity:entity insertIntoManagedObjectContext:context]) {
NSError *error = nil;
if (![context obtainPermanentIDsForObjects:@[self] error:&error]) {
@throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo];
}
}
return self;
}
+ (NSArray*)createMultipleObjects:(NSUInteger)count withEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)context {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
for (NSUInteger i = 0; i < count; ++i) {
[array addObject:[[self alloc] initWithEntity:entity insertIntoManagedObjectContext:context]];
}
NSError *error = nil;
if (![context obtainPermanentIDsForObjects:array error:&error]) {
@throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo];
}
return array;
}
@end
现在,在第一个中,您需要付费进入数据库并为创建的每个实体创建一个 ID,但这并不多,而且它发生在后台线程中,并且每次下降都很短......
哦,好吧,它不是最好的,但它提供了有用的。此外,第二个创建多个相同对象,并同时获取它们的永久 ID。
您还可以使用直接连接到 PSC 的 MOC,并监视 DidChange 事件,但这与旧方法相同。
不幸的是,你不能有一个单独的 MOC 只发出 persistentID 请求并传递 ObjectID,尽管你可以有一个单独的 MOC 在 DB 中制作原型对象,并为你提供它们的 ObjectID。
原型工厂是一种相当常见的模式,如果你走这条路,当最终的错误修复到这里时,很容易做出微小的改变。
编辑
回应斯文...
如果您要创建新的复杂图表,则需要在创建后立即获取永久 ID。要减少对商店的点击次数,您应该全部创建它们,然后立即获取 ID,然后开始连接它们。
老实说,所有这些都是为了解决当前存在的错误,这些错误对于中小型更新来说是值得解决的。修复错误后,您的代码将是相同的(无需获取)。因此,我建议将这种方法用于较小的进口。
如果您正在进行大规模更新,我建议使用“旧”方法。创建一个直接连接到 PSC 的新 MOC。在那里进行所有更改,并让您的“实时”上下文从那些 DidSave 通知中合并。
最后,关于永久 ID 对数据库的影响。可以丢弃 MOC。磁盘被击中,元数据被改变,但对象没有被持久化。
老实说,我没有做一个大的测试来看看是否有任何空白空间,所以你可能想这样做,然后和我一起回来。
查看磁盘上实际的数据库文件大小,然后创建 10000 个对象,然后获取持久 ID,释放 MOC,再查看大小。
如果有影响,您可以尝试删除对象,或在大更新后对数据库运行清理以查看是否有效。
如果您要创建大量可能会丢弃的对象,则无需访问数据库。您可能只想直接附加到 PSC 并使用旧的忠实通知。