core-datauimanageddocument

UIManagedDocument Creation in ViewDidLoad


After some research I am still unsure on when / how I should create my UIManagedDocument.

@interface ViewController ()
@property (strong, nonatomic) UIManagedDocument *document;
@end

@implementation ViewController

- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];

NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = @"MyDocument";
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];

BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];

if (fileExists) {
    [self.document openWithCompletionHandler:^(BOOL success) {
        NSLog(@"Exsits dont create again");
        if (success) [self documentIsReadyCreateAndObject];
        if (!success) NSLog(@"cound not open document at %@", url);
    }];
}
else {
    // create it
    [self.document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
        NSLog(@"Create it");
        if (success) [self documentIsReadyCreateAndObject];
        if (!success) NSLog(@"cound not create document at %@", url);
    }];
}
}

- (void) documentIsReadyCreateAndObject
{
if (self.document.documentState == UIDocumentStateNormal) {
    NSLog(@"document is ready - create obj");
    Car *demo = [NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:self.document.managedObjectContext];
    demo.carName = @"xxxxx";
}
else {
    NSLog(@"Not ready to go");
}
}

- (void) fetchAndPrint
{
if (self.document.documentState == UIDocumentStateNormal) {
    NSLog(@"document is ready - print objs");
    NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:@"Car"];
    NSArray *results = [self.document.managedObjectContext executeFetchRequest:request error:nil];

    for (Car *aLog in results) {
        NSLog(@"\nNAME: %@", aLog.carName);
    }
}
else {
    NSLog(@"Not ready to go");
}
}

@end

Solution

  • View Controller vs. App Delegate

    The best time to create your UIManagedDocument depends a little on the situation, but I find that in most cases the app's delegate is the best place for it. A view controller is really not the place to create a database. Most of the time, you'll be using that database in multiple places in your app, so it wouldn't really be the task of one specific view controller to create it. If the design of your app changes such that that view controller is not the first controller on screen, you have to take all that code and put it in some other view controller.

    Since a Core Data backed model usually needs to be accessed from many different view controllers, I use the app delegate for that. As soon as your app is launched, it will create or open a database that view controllers can use pretty much immediately.

    That doesn't mean that you have to access your document from the app delegate as well. There's a lot of debate about whether that's good practice or not, but I prefer to pass the document to whatever object needs so that it doesn't depend on the app delegate for its model.

    Most of the time, the only reason you pass a UIManagedDocument is for its NSManagedObjectContext, so you could consider just passing that if you don't need any other document-related properties. Also, if you just pass one NSManagedObject, you automatically have access to its context, so that could reduce the number of times you have to pass your document.

    Migration

    I'll answer your last question first: no, using the traditional Core Data stack or UIManagedDocument does not matter with regards to migration (lightweight or using mapping models). UIManagedDocument has a persistentStoreOptions property that you can use to handle most migrations for you. Even if you need a mapping model, you can create that, add it to your bundle and if you made the right mappings, it will do it all for you.