5

I've worked through the Stanford course and setup my first app and core data as in the lecture. Approximately like this (I will shift the code into the app delegate now):

- (void)setupFetchedResultsController
{
    NSError *error = nil;
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"MainCategory"];
    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"position" ascending:YES]];
    [self.budgetDatabase.managedObjectContext executeFetchRequest:request error:&error];

    self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request
                                                                       managedObjectContext:self.budgetDatabase.managedObjectContext
                                                                         sectionNameKeyPath:nil
                                                                                  cacheName:nil];
}

-(void)useDocument
{
    if(![[NSFileManager defaultManager]fileExistsAtPath:[self.budgetDatabase.fileURL path]]){
        [self.budgetDatabase saveToURL:self.budgetDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            [self setupFetchedResultsController];
        }];
    } else if (self.budgetDatabase.documentState == UIDocumentStateClosed){
        [self.budgetDatabase openWithCompletionHandler:^(BOOL success){
            [self setupFetchedResultsController];
        }];
    } else if (self.budgetDatabase.documentState == UIDocumentStateNormal){
        [self setupFetchedResultsController];
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    //Initialize database
    [super viewWillAppear:animated];
    if(!self.budgetDatabase){
        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentationDirectory inDomains:NSUserDomainMask] lastObject];
        [url URLByAppendingPathComponent:@"BudgetDatabase"];
        self.budgetDatabase = [[UIManagedDocument alloc]initWithFileURL:url];
    }
}

The code in the Apple template (if you check "CoreData" when creating a Xcode project) looks very different and more complex. What's the difference to this UIManagedDocument? Is there a better or worse?

Daniel Martín
  • 7,815
  • 1
  • 29
  • 34
MichiZH
  • 5,587
  • 12
  • 41
  • 81
  • UIManagedDocument works fine but there is still a lot of work to do particularly if you intend using iCloud integration. If your app needs to integrate multiple stores into a single managedObjectContext then UIManagedDocument won't help you. For more detail on how to get UIManagedDocument and iCloud to play nicely take a look at this link http://ossh.com.au/design-and-technology/software-development/uimanageddocument-icloud-integration/ – Duncan Groenewald Jan 02 '14 at 12:15

3 Answers3

3

The UIManagedDocument is designed for applications that have documents, hence the name. The Stanford class is using it to skip over the construction of Core Data to make it "easier" for the student. Unfortunately they are making life harder for you in the long run.

Do not use UIManagedDocument. Start with the Apple templates, learn how to stand up the Core Data stack. You will gain more knowledge that way, have a better understanding of what the code is doing (less magic) and will progress as a developer.

UIManagedDocument has a lot of sharp edges and it is difficult to work with when things start getting complex. Skip it.

Update

UIManagedDocument is not designed to be the single Core Data stack for an application, it is meant for document based applications.

The fact that you cannot guarantee a save (without hacking at it) is a big risk. It is also an opaque construct and you are not supposed to dive down into its private context.

The fact that it will save on its own with no way to stop it makes it dangerous in my book. It is very easy for you to be wanting the context not saved (heavy UI, playing a video, etc.) and it decides to save. Bad UX.

Add on top of that, it is intended to be used with external file structures that are complicated to work with and it gets even more risky.

What does it save you? Nothing. It is not a code savings because the 6 lines of code to stand up a normal Core Data stack are replaced by a lot of asynchronous code to stand up and deploy a UIManagedDocument.

How do you handle a migration? What happens when the migration requires extra effort beyond a lightweight migration?

Lots of things to consider.

Number one in my book is the random and async saving. I just don't like the idea of giving up that control.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • Marcus, I don't know if Stanford uses it for make the life of students easier but yes, I agree that following also the traditional way (but also the new since a developer should stay updated on new stuff) *is progress as a developer*. – Lorenzo B Jan 01 '14 at 21:17
  • `UIManagedDocument` is not the new way as Apple doesn't use it in single MOC app designs (nor should they, it is too opaque). It is not meant for single MOC apps. It is meant for document based applications but people are using it as a shortcut :( – Marcus S. Zarra Jan 01 '14 at 21:45
  • Yep. I perfectly agree with you. Also my answer stated this, i.e. useful for document based apps. In a first moment (but only at this time) it could be considered as a good alternative to background stuff that can become complex in Core Data. Happy to talk with a Guru like you are ;) – Lorenzo B Jan 01 '14 at 21:51
  • Marcus, can you give some examples of the sharp edges? I've been messing with UIManagedDocument for about a year now and it has been pretty nice for me. I'm using it with a shopping application with a semi-complex model table. i'm not baiting here either - i know you're a respected voice in core data which is why i'm asking - so i can maybe understand your view as well – Jonathon Hibbard Jan 10 '14 at 03:52
  • @JonathonHibbard Updated the answer with a *little* more detail on `UIManagedDocument`. – Marcus S. Zarra Jan 10 '14 at 18:52
1

Simple response is the following. The UIManagedDocument abstract the interaction with Core Data Stack.

With UIManagedDocument saving is handled automatically and it is generally performed in a async fashion within a background thread. In addition, it encloses some features to deal with iCloud stuff. In a generic way it can be considered as a wrapper to your Core Data stack.

There is no better or worse approach. The UIManagedDocument is designed to work with document based applications. See UIDocument class reference to further details.

About the Core Data Stack there is nothing complex or difficult. There is only more code. But under the hood the UIManagedDocument wraps that code for you.

The code for Core Data stack can be easily reduced. A good post on how to simplify the template provided by Apple can be found in Core Data Stack by @jrturton. In particular, the code simplifies in 6 steps that can be followed through a logical flow.

As suggested in a previous answer.

The stuff related to the NSFetchedResultsController should stay in a controller class. For example it could stay in a specific UIViewController class, a UITableViewController class or in a class from which other classes can extend from (i.e. a base UIViewController class).

Hope it helps.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
0

I personally also started with context on UIDocument as suggested on Stanford courses which is good for a simple application and it's the easiest approach to start with. When my app grew and I needed to access coredata throughout the application, I had to handle the extra code for accessing/opening/creating the document in different life stages of the app.

I then moved to Apple template and I am very happy about that. All is in appDelegate anyway. I would suggest you read this for handling Core data on background threads with parent-child relationships Multi-Context CoreData.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
Martin Koles
  • 5,177
  • 8
  • 39
  • 59
  • But I don't understand the difference..the underlying database is the same isn't it? This is just a different way to acccess it? Thx for the link, I'll check it out – MichiZH Dec 31 '13 at 11:09
  • CoreData can have many types of underlying sources for databases, they can even be remote storages in the cloud. The most common is an sqlite type database, which is an sqlite in a single file. You access the database through its context, which is like a scratchpad for making changes, and it needs to be saved. With UIDocument, you create a new file, specify db type and model and start using it. Apple template does this for you and you don't have to check document state, you just access it's context with AppDelegate's context and then save. I didn't like the async open of UIDocument. – Martin Koles Dec 31 '13 at 11:33
  • How your reply answers to the OP question? Thanks. – Lorenzo B Dec 31 '13 at 16:40