Core data 永久的NSManagedObjectd不是那么永久吗?

Core data 永久的NSManagedObjectd不是那么永久吗?,core-data,nsmanagedobject,magicalrecord,Core Data,Nsmanagedobject,Magicalrecord,我在处理CoreData中的对象ID时遇到问题。为了方便起见,我使用MagicalRecord,它有3个上下文:一个专用队列工作上下文、一个UI的主队列上下文和工作上下文的父上下文,以及一个作为主上下文父上下文的专用队列保存上下文 我的目标是在工作上下文中创建一个对象,保存到持久性存储,将其objectID URL保存到NSUserDefaults,然后能够稍后使用objectID提取该MO。然而,我发现在保存对象的永久ID之后,它正在发生变化 在下面的控制台输出中,您可以看到,在我请求永久ID

我在处理CoreData中的对象ID时遇到问题。为了方便起见,我使用MagicalRecord,它有3个上下文:一个专用队列工作上下文、一个UI的主队列上下文和工作上下文的父上下文,以及一个作为主上下文父上下文的专用队列保存上下文

我的目标是在工作上下文中创建一个对象,保存到持久性存储,将其objectID URL保存到NSUserDefaults,然后能够稍后使用objectID提取该MO。然而,我发现在保存对象的永久ID之后,它正在发生变化

在下面的控制台输出中,您可以看到,在我请求永久ID后,我返回的值是“F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseCount/p1”,但稍后当我列出CD中的所有对象时,唯一的对象ID是“F474F6EE-A225-456B-92EF-AB1407336F15/CDBaseCount/p2”。p1对p2,发生了什么

代码:

控制台输出:

  > +[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>)"
  )}
+[NSManagedObjectContext(MagicalRecord)MR_contextWithStoreCoordinator:(0xa7c9b0)->已创建:上下文***主线程***
>计数:0
>所有帐户=(
> )
>-[NSManagedObjectContext(MagicalSaves)MR_saveWithErrorCallback:](0x8353de0)->保存:上下文***主线程***
>-[NSManagedObjectContext(MagicalSaves)MR_saveWithErrorCallback:(0x8195450)->保存:**默认***上下文***主线程***
>-[NSManagedObjectContext(MagicalSaves)MR_saveWithErrorCallback:(0x83522a0)->保存:**后台保存***上下文***主线程***
>临时a.objectID=0x8187ee0
>perm a.objectID=0x8355800
>计数:1
>所有帐户=(
“(实体:CDBaseCount;id:0x844a4c0;数据:)”
)
>现有对象错误:错误域=NSCOCAERRORDOMAIN代码=133000“该操作无法完成。(Cocoa错误133000。)”用户信息=0x864d8c0{NSACTIVEDOBJECTSERRORKEY=(
“(实体:CDBaseCount;id:0x86405c0;数据:)”
)}

简而言之,不要这样做:)

-objectID
在应用程序启动之间不可靠。在以下条件下,保证其唯一性和可靠性:

  • 在应用程序的单个生命周期内
  • 以其原始对象形式(不是URL或NSString形式)
  • -objectID
    视为永久唯一标识符存储在持久性存储区之外会经常失败。核心数据在对象的生命周期内多次更改
    -objectID
    的基本细节


    如果你需要一个外部可靠的唯一,那么你需要自己创建一个。我通常建议将
    [[NSProcessInfo processInfo]globallyUniqueString]
    添加到任何需要外部引用的唯一实体<代码>-awakeFromInsert
    是一个很好的地方。

    这可能是因为您使用的是嵌套上下文

    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    
    static NSArray *fetchAllPersons(NSManagedObjectContext *moc);
    static NSManagedObjectModel *managedObjectModel();
    static NSManagedObjectContext *createManagedObjectContext();
    static NSURL *desktopDirectoryURL(void);
    
    static void testObjectID(void);
    
    
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                testObjectID();
            });
        }
        dispatch_main();
        return 0;
    }
    
    
    
    
    static void testObjectID(void)
    {
        NSManagedObjectContext *c = createManagedObjectContext();
        [c performBlock:^{
    
            NSArray *all = fetchAllPersons(c);
            NSLog(@"count: %lu", all.count);
            NSLog(@"all accounts = %@", all);
    
            NSManagedObject *a = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:c];
            [a setValue:@"foo" forKey:@"name"];
    
            NSLog(@"temp a.objectID = %@", a.objectID);
            NSError *error = nil;
            NSCAssert([c obtainPermanentIDsForObjects:@[a] error:&error], @"perm id error: %@", error);
            NSLog(@"perm a.objectID = %@", a.objectID);
    
            NSCAssert([c save:&error], @"Save failed: %@", error);
    
            NSURL *u = a.objectID.URIRepresentation;
    
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                NSManagedObjectContext *d = createManagedObjectContext();
    
                NSArray *all = fetchAllPersons(c);
                NSLog(@"count: %lu", all.count);
                NSLog(@"all accounts = %@", all);
    
                NSManagedObjectID *i = [d.persistentStoreCoordinator managedObjectIDForURIRepresentation:u];
                NSError *objWithIdError = nil;
                NSManagedObject *o = [d existingObjectWithID:i error:&objWithIdError];
                NSCAssert(o != nil, @"existing object error: %@", objWithIdError);
    
                NSLog(@"o = %@", o);
                NSLog(@"o.objectID = %@", o.objectID);
            });
        }];
    }
    
    
    static NSArray *fetchAllPersons(NSManagedObjectContext *moc)
    {
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
        NSError *error = nil;
        NSArray *result = [moc executeFetchRequest:request error:&error];
        NSCAssert(result != nil, @"Fetch failed: %@", error);
        return result;
    }
    
    static NSManagedObjectModel *managedObjectModel()
    {
        static NSManagedObjectModel *mom = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSEntityDescription *personEntity = [[NSEntityDescription alloc] init];
            [personEntity setName:@"Person"];
    
            NSAttributeDescription *nameAttribute = [[NSAttributeDescription alloc] init];
    
            [nameAttribute setName:@"name"];
            [nameAttribute setAttributeType:NSStringAttributeType];
    
            [personEntity setProperties:@[nameAttribute]];
    
            mom = [[NSManagedObjectModel alloc] init];
            [mom setEntities:@[personEntity]];
        });
        return mom;
    }
    
    
    static NSManagedObjectContext *createManagedObjectContext()
    {
        static NSPersistentStoreCoordinator *coordinator;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: managedObjectModel()];
    
            NSString *STORE_TYPE = NSSQLiteStoreType;
            NSString *STORE_FILENAME = @"foobar.db";
    
            NSError *error;
            NSURL *url = [desktopDirectoryURL() URLByAppendingPathComponent:STORE_FILENAME];
    
            NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE
                                                                    configuration:nil URL:url options:nil
                                                                            error:&error];
    
            if (newStore == nil) {
                NSLog(@"Store Configuration Failure\n%@",
                      ([error localizedDescription] != nil) ?
                      [error localizedDescription] : @"Unknown Error");
            }
        });
    
        NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [moc setPersistentStoreCoordinator:coordinator];
    
        return moc;
    }
    
    
    static NSURL *desktopDirectoryURL(void)
    {
        static NSURL *URL;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSFileManager *fileManager = [[NSFileManager alloc] init];
            NSError *error;
            URL = [fileManager URLForDirectory:NSDesktopDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
            NSCAssert(URL != nil, @"Could not access Desktop directory: %@", [error localizedDescription]);
        });
        return URL;
    }
    
    #导入
    #进口
    静态NSArray*fetchAllPersons(NSManagedObjectContext*moc);
    静态NSManagedObjectModel*managedObjectModel();
    静态NSManagedObjectContext*createManagedObjectContext();
    静态NSURL*desktopDirectoryURL(无效);
    静态void testObjectID(void);
    int main(int argc,const char*argv[]
    {
    @自动释放池{
    调度异步(调度获取全局队列(0,0)^{
    testObjectID();
    });
    }
    调度_main();
    返回0;
    }
    静态void testObjectID(void)
    {
    NSManagedObjectContext*c=createManagedObjectContext();
    [c性能块:^{
    NSArray*all=fetchAllPersons(c);
    NSLog(@“计数:%lu”,全部.count);
    NSLog(@“所有帐户=%@”,全部);
    NSManagedObject*a=[NSEntityDescription insertNewObjectForEntityForName:@“Person”在ManagedObject上下文中:c];
    [a setValue:@“foo”forKey:@“name”];
    NSLog(@“temp a.objectID=%@”,a.objectID);
    n错误*错误=nil;
    NSCAssert([c获取永久对象:@[a]错误:&错误],@“perm id error:%@”,错误);
    NSLog(@“perm a.objectID=%@”,a.objectID);
    NSCAssert([c保存:&错误],@“保存失败:%@”,错误);
    NSURL*u=a.objectID.Uri表示法;
    调度异步(调度获取全局队列(0,0)^{
    NSManagedObjectContext*d=createManagedObjectContext();
    NSArray*all=fetchAllPersons(c);
    NSLog(@“计数:%lu”,全部.count);
    NSLog(@“所有帐户=%@”,全部);
    NSManagedObjectID*i=[d.persistentStoreCoordinator ManagedObjectdForUriRepresentation:u];
    n错误*objWithIdError=nil;
    NSManagedObject*o=[d个ID为:i的现有对象错误:&objWithIdError];
    NSCAssert(o!=nil,@“现有对象错误:%@”,objWithIdError);
    NSLog(@“o=%@”,o);
    NSLog(@“o.objectID=%@”,o.objectID);
    });
    }];
    }
    静态NSArray*fetchAllPersons(NSManagedObjectContext*moc)
    {
    NSFetchRequest*request=[NSFetchRequest fetchRequestWithEntityName:@“Person”];
    n错误*错误=nil;
    NSArray*结果=[moc executeFetchRequest:请求错误:&错误];
    NSCAssert(结果!=nil,@“获取失败:%@”,错误);
    返回结果;
    }
    静态NSManagedObjectModel*managedObjectModel()
    {
    静态NSManagedObjectModel*mom=nil;
    静态调度一次;
    一次发送(一次发送)^{
    NSEntityDescription*personEntity=[[NSEntityDescription alloc]init];
    [personEntity集合名:@“Person”];
    NSAttributedDescription*nameAttribute=[[NSAttributedDescription alloc]init];
    [名称属性集合名称:@“名称”];
    [nameAttribute setAttributeType:NSStringAttributeType];
    [personEntity setProperties:@[nameAttribute];
    mom=[[NSManagedObjectModel alloc]init];
    [mom setEntities:@[personEntity]];
    });
    返回妈妈;
    }
    静态NSManagedObjectContext*createManagedObjectContext()
    {
    静态NSPersistentStoreCoordinator*协调器;
    静态调度一次;
    调度
    
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    
    static NSArray *fetchAllPersons(NSManagedObjectContext *moc);
    static NSManagedObjectModel *managedObjectModel();
    static NSManagedObjectContext *createManagedObjectContext();
    static NSURL *desktopDirectoryURL(void);
    
    static void testObjectID(void);
    
    
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                testObjectID();
            });
        }
        dispatch_main();
        return 0;
    }
    
    
    
    
    static void testObjectID(void)
    {
        NSManagedObjectContext *c = createManagedObjectContext();
        [c performBlock:^{
    
            NSArray *all = fetchAllPersons(c);
            NSLog(@"count: %lu", all.count);
            NSLog(@"all accounts = %@", all);
    
            NSManagedObject *a = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:c];
            [a setValue:@"foo" forKey:@"name"];
    
            NSLog(@"temp a.objectID = %@", a.objectID);
            NSError *error = nil;
            NSCAssert([c obtainPermanentIDsForObjects:@[a] error:&error], @"perm id error: %@", error);
            NSLog(@"perm a.objectID = %@", a.objectID);
    
            NSCAssert([c save:&error], @"Save failed: %@", error);
    
            NSURL *u = a.objectID.URIRepresentation;
    
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                NSManagedObjectContext *d = createManagedObjectContext();
    
                NSArray *all = fetchAllPersons(c);
                NSLog(@"count: %lu", all.count);
                NSLog(@"all accounts = %@", all);
    
                NSManagedObjectID *i = [d.persistentStoreCoordinator managedObjectIDForURIRepresentation:u];
                NSError *objWithIdError = nil;
                NSManagedObject *o = [d existingObjectWithID:i error:&objWithIdError];
                NSCAssert(o != nil, @"existing object error: %@", objWithIdError);
    
                NSLog(@"o = %@", o);
                NSLog(@"o.objectID = %@", o.objectID);
            });
        }];
    }
    
    
    static NSArray *fetchAllPersons(NSManagedObjectContext *moc)
    {
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
        NSError *error = nil;
        NSArray *result = [moc executeFetchRequest:request error:&error];
        NSCAssert(result != nil, @"Fetch failed: %@", error);
        return result;
    }
    
    static NSManagedObjectModel *managedObjectModel()
    {
        static NSManagedObjectModel *mom = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSEntityDescription *personEntity = [[NSEntityDescription alloc] init];
            [personEntity setName:@"Person"];
    
            NSAttributeDescription *nameAttribute = [[NSAttributeDescription alloc] init];
    
            [nameAttribute setName:@"name"];
            [nameAttribute setAttributeType:NSStringAttributeType];
    
            [personEntity setProperties:@[nameAttribute]];
    
            mom = [[NSManagedObjectModel alloc] init];
            [mom setEntities:@[personEntity]];
        });
        return mom;
    }
    
    
    static NSManagedObjectContext *createManagedObjectContext()
    {
        static NSPersistentStoreCoordinator *coordinator;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: managedObjectModel()];
    
            NSString *STORE_TYPE = NSSQLiteStoreType;
            NSString *STORE_FILENAME = @"foobar.db";
    
            NSError *error;
            NSURL *url = [desktopDirectoryURL() URLByAppendingPathComponent:STORE_FILENAME];
    
            NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE
                                                                    configuration:nil URL:url options:nil
                                                                            error:&error];
    
            if (newStore == nil) {
                NSLog(@"Store Configuration Failure\n%@",
                      ([error localizedDescription] != nil) ?
                      [error localizedDescription] : @"Unknown Error");
            }
        });
    
        NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [moc setPersistentStoreCoordinator:coordinator];
    
        return moc;
    }
    
    
    static NSURL *desktopDirectoryURL(void)
    {
        static NSURL *URL;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSFileManager *fileManager = [[NSFileManager alloc] init];
            NSError *error;
            URL = [fileManager URLForDirectory:NSDesktopDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
            NSCAssert(URL != nil, @"Could not access Desktop directory: %@", [error localizedDescription]);
        });
        return URL;
    }
    
    count: 0
    all accounts = (
    )
    temp a.objectID = 0x10180e640 <x-coredata:///Person/tB1D48677-0152-4DA9-8573-7C7532863B4E2>
    perm a.objectID = 0x101901bb0 <x-coredata://275C90E5-2598-4DFA-BF4C-E60A336E8BE4/Person/p1>
    count: 1
    all accounts = (
        "<NSManagedObject: 0x10180e5b0> (entity: Person; id: 0x101901bb0 <x-coredata://275C90E5-2598-4DFA-BF4C-E60A336E8BE4/Person/p1> ; data: {\n    name = foo;\n})"
    )
    o = <NSManagedObject: 0x100416530> (entity: Person; id: 0x100415b60 <x-coredata://275C90E5-2598-4DFA-BF4C-E60A336E8BE4/Person/p1> ; data: {
        name = foo;
    })
    o.objectID = 0x100415b60 <x-coredata://275C90E5-2598-4DFA-BF4C-E60A336E8BE4/Person/p1>