Permanent NSManagedObjectID not so permanent?

后端 未结 2 1024
北恋
北恋 2020-12-05 08:23

I\'m having trouble dealing with object IDs in CoreData. I\'m using MagicalRecord for convenience and have 3 contexts: a private queue working context, a main queue context

相关标签:
2条回答
  • 2020-12-05 09:07

    Short answer is, don't do that :)

    -objectID is not reliable between launches of your application. It is guaranteed to be unique and reliable under the following conditions:

    1. Within a single lifecycle of the application
    2. In its original object form (not in URL or NSString form)

    Treating the -objectID as a permanent unique identifier to be stored outside of the persistent store is going to fail you fairly often. Core Data changes the underlying details of the -objectID many times during the life of the object.

    If you need an externally reliable unique then you need to create one yourself. I generally recommend adding a [[NSProcessInfo processInfo] globallyUniqueString] to any entity that needs an externally reference-able unique. -awakeFromInsert is a great place to do that.

    0 讨论(0)
  • 2020-12-05 09:21

    This may be because you're using nested context.

    #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;
    }
    

    Outputs:

    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>
    
    0 讨论(0)
提交回复
热议问题