Search code examples
iosobjective-ccore-datansmanagedobjectcontext

Managed object context not saved


I am trying to load a table view with cells that represents people, loaded from core data. This is how I get the context:

@property (nonatomic,strong) NSManagedObjectContext* managedObjectContext;

...

- (NSManagedObjectContext*) managedObjectContext {
    if(!_managedObjectContext) {
        NSFileManager* manager= [NSFileManager defaultManager];
        NSURL* URL= [manager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject;
        URL= [URL URLByAppendingPathComponent:@"PeopleDocument"];
        UIManagedDocument* document= [[UIManagedDocument alloc]initWithFileURL:URL];

        if([manager fileExistsAtPath:URL.path]) {
            [document openWithCompletionHandler:^(BOOL success) {
            }];
        } else {
            [document saveToURL:URL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            }];
        }
        NSManagedObjectContext* context= [document managedObjectContext];
        _managedObjectContext= context;
    }
    return _managedObjectContext;
}

Then just the first time that I run the app I insert a new entity and save the context:

[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext: self.managedObjectContext];
[self.managedObjectContext save:NULL];

I also tried to log the result of save:, it returns YES and there's no error. But the context isn't truly saved: the second time that I run the app the fetched entities array is empty.

Update

Something even stranger happened: reading this answer to another similar question, I've found a method to force the document to be saved:

- (void) save {
    NSError *error = nil;

    if (![self.managedObjectContext save:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    [self.managedDocument saveToURL:self.managedDocument.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success)
    {
        NSLog(@"Saved: %d",success);
    }];

}

So I execute this code the first time that I run the app:

#if FIRST_TIME
    [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext: self.managedObjectContext];
    [self save];
#endif

After it, if I set FIRST_TIME to zero, the second time that I run the app I get empty records. But if the 3rd time that I run the app I set again FIRST_TIME to 1, then I get all the records that I created before (plus the one that gets created). This means that if I create and save new entities, all the entities that I created before are fetched correctly, otherwise no entity is fetched.

PS: I double checked: the managed object context is the exact one returned by self.managedDocument.managedObjectContext.


Solution

  • I just changed my way to create the managed object context. Instead of using a UIManagedDocument, I created the context with alloc+initWithConcurrencyType:, then I set it's persistent store coordinator:

    - (NSManagedObjectContext*) managedObjectContext {
        if(!_managedObjectContext) {
            NSURL* URL= [[NSBundle mainBundle] URLForResource:@"People" withExtension:@"momd"];
            NSManagedObjectModel* model= [[NSManagedObjectModel alloc]initWithContentsOfURL:URL];
            NSPersistentStoreCoordinator* storeCoordinator= [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel: model];
            NSURL* storeURL= [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].lastObject;
            storeURL= [storeURL URLByAppendingPathComponent:@"MOC.sqlite"];
    
            NSError* error;
            [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
            if(error) {
                NSLog(@"Cannot create new store %@",error);
                return nil;
            }
    
            _managedObjectContext= [[NSManagedObjectContext alloc]initWithConcurrencyType: NSMainQueueConcurrencyType];
            _managedObjectContext.persistentStoreCoordinator= storeCoordinator;
        }
    
        return _managedObjectContext;
    }
    

    I believe that also the other way is correct, but maybe I had to save the document in another way.