我在处理CoreData中的对象ID时遇到麻烦。为了方便起见,我使用MagicalRecord并具有3个上下文:私有(private)队列工作上下文,UI的主队列上下文和工作上下文的父级,以及作为主上下文的父级的私有(private)队列保存上下文。
我的目标是在工作上下文中创建一个对象,保存到持久性存储中,将其objectID URL保存到NSUserDefaults,然后稍后可以使用objectID提取该MO。但是,我发现的是,保存对象后,永久性ID发生了变化。
在下面的控制台输出中,您可以看到,在我请求永久ID之后,返回的值是“F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseAccount/p1”,但是稍后在列出CD中的所有对象时,那里唯一的对象具有ID“F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseAccount/p2”。 p1 vs p2,发生了什么事?
代码:
NSManagedObjectContext *c = [NSManagedObjectContext MR_contextThatPushesChangesToDefaultContext];
[c performBlockAndWait:^{
NSArray *all = [CDBaseAccount MR_findAllInContext:c];
NSLog(@"count: %d", all.count);
NSLog(@"all accounts = %@", all);
CDBaseAccount *a = [CDBaseAccount MR_createInContext:c];
a.accountName = @"foo";
[c MR_saveNestedContexts];
NSLog(@"temp a.objectID = %@", a.objectID);
NSError *error;
if (![c obtainPermanentIDsForObjects:@[a] error:&error]) {
NSLog(@"perm id error: %@", error);
return;
}
NSLog(@"perm a.objectID = %@", a.objectID);
NSURL *u = a.objectID.URIRepresentation;
dispatch_async(dispatch_get_main_queue(), ^{
NSManagedObjectContext *d = [NSManagedObjectContext MR_defaultContext];
NSArray *all = [CDBaseAccount MR_findAllInContext:d];
NSLog(@"count: %d", all.count);
NSLog(@"all accounts = %@", all);
NSManagedObjectID *i = [d.persistentStoreCoordinator managedObjectIDForURIRepresentation:u];
NSError *objWithIdError = nil;
NSManagedObject *o = [d existingObjectWithID:i error:&objWithIdError];
if (objWithIdError != nil) {
NSLog(@"existing object error: %@", objWithIdError);
return;
}
NSLog(@"o = %@", o);
NSLog(@"o.objectID = %@", o.objectID);
});
}];
控制台输出:
> +[NSManagedObjectContext(MagicalRecord) MR_contextWithStoreCoordinator:](0xa7c9b0) -> Created <NSManagedObjectContext: 0x83522a0>: Context *** MAIN THREAD ***
> count: 0
> all accounts = (
> )
> -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x8353de0) -> Saving <NSManagedObjectContext: 0x8353de0>: Context *** MAIN THREAD ***
> -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x8195450) -> Saving <NSManagedObjectContext: 0x8195450>: *** DEFAULT *** Context *** MAIN THREAD ***
> -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x83522a0) -> Saving <NSManagedObjectContext: 0x83522a0>: *** BACKGROUND SAVE *** Context *** MAIN THREAD ***
> temp a.objectID = 0x8187ee0 <x-coredata:///CDBaseAccount/tF392AC6A-3539-4F39-AC53-35F9E5B3C9322>
> perm a.objectID = 0x8355800 <x-coredata://F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseAccount/p2>
> count: 1
> all accounts = (
"<CDBaseAccount: 0x844ca60> (entity: CDBaseAccount; id: 0x844a4c0 <x-coredata://F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseAccount/p1> ; data: <fault>)"
)
> existing object error: Error Domain=NSCocoaErrorDomain Code=133000 "The operation couldn’t be completed. (Cocoa error 133000.)" UserInfo=0x864d8c0 {NSAffectedObjectsErrorKey=(
"<CDBaseAccount: 0x864b8c0> (entity: CDBaseAccount; id: 0x86405c0 <x-coredata://F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseAccount/p2> ; data: <fault>)"
)}
最佳答案
简短的答案是,不要那样做:)
两次启动应用程序之间-objectID
不可靠。在以下情况下,它保证是唯一且可靠的:
将
-objectID
视为要存储在持久性存储之外的永久唯一标识符,这会使您经常失败。在对象的生存期内,核心数据会多次更改-objectID
的底层详细信息。如果您需要一个外部可靠的唯一标识,那么您需要自己创建一个。我通常建议向需要外部可引用的唯一性的任何实体添加
[[NSProcessInfo processInfo] globallyUniqueString]
。 -awakeFromInsert
是执行此操作的好地方。关于core-data - 永久的NSManagedObjectID不是那么永久的吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12218396/