One or many UIManagedDocuments

356 Views Asked by At

Ok, let's say I'm making a bird watch app.

There's an "official" birds database. Which is stored in one UIManagedDocument. It's used to populate UITableView with all the birds and a little detailed view for each of them with pictures and data. This database will be upgraded in the future with more bird species.

Then the user can go out to the countryside and take pictures of birds. He adds them to another section of the app, called the "diary" and when he identifies the bird he then links it with one "official" bird. This information (all user collected data) should be backed up with iCloud. And it's also used to populate the diary's UITableView and detailed views.

From a diary's detailed view you can go to the "official" bird's detailed view. And from that view you can go to a list with all the registers of that bird in the user's diary.

The question is: Should I use one UIManagedDocument for each one of the user's entries? How does that work with a UITableView with thumbnails?

3

There are 3 best solutions below

3
On

A UIDocument is a management class for physical File Wrappers. A UIManagedDocument is a subclass of that which provides a CoreData stack.

A File Wrapper is not much more than an abstraction for a folder or file. For UIManagedDocument that folder contains a SQLite database which the CoreData stack connects to.

You wouldn't use individual Documents for Diary entries any more than you would use an individual Word document for each paragraph of writing.

Since your app sounds more like what Apple calls a "Shoebox app" in which one user has a single pile of data which they add to and subtract from theres no real need to use the Document Architecture. However in saying this UIManagedDocument provides you with a free stack so may prove useful.

If it was me constructing this app I might take this approach.

  1. A read-only database for your official birds. This database is downloaded on first launch & whenever it needs updates. You shouldn't attempt to put this in your bundle as its going to be pretty big. It will not be backed up at any point.

  2. A read-write database which holds your Diary entries. This database is backed to to iCloud and isnt touched across upgrades of the Bird database.

  3. Loosely couple the two databases by using GUIDs rather than CoreData relationships.

enter image description here

e.g The GUID for a Mallard Duck might be DUCK1234 . Write that GUID as a attribute (e.g birdGUID ) on your diary entry. To find all Diary entries for Mallards run a query on "birdGUID == 'DUCK1234'" on your Diary database and you get all the times you spotted one.

The reason for doing this is that you can upgrade the official Bird Database without worrying about harming the user data. Say you purchase a better/cheaper database or a different one which has bird calls you can adjust the Schema to cope with that.

EDIT

One approach (an easy one) is to build your stack with two NSPersistentStores

NSPersistentStoreCoordinator *myPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];

NSDictionary *readonly_options = @{NSReadOnlyPersistentStoreOption:@YES};

[myPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:officialBirdStoreURL options:readonly_options error:&error];

NSDictionary *readwrite_opts = @{NSMigratePersistentStoresAutomaticallyOption:@YES,
  NSInferMappingModelAutomaticallyOption:@YES};

[myPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:diaryStoreURL options:readwrite_opts error:&error];

NSManagedObjectContext *workingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSMainQueueConcurrencyType];

workingContext.persistentStoreCoordinator = myPersistentStoreCoordinator;

Im not going to fully explain this as theres many excellent Core Data tutorials but take note of setting the NSReadOnlyPersistentStoreOption on your Bird Database.

This doesn't involve using UIManagedDocument as you don't get enough control over the stack.

To summarise, The stack from bottom to top.

  • UIManagedDocument - Model Controller. Handles File Wrapper mechanics and provides free stack. Not required . May make Multi Document apps easier (or not).
  • NSManagedObjectModel - Model , The Schema of your Core Data Model.
  • NSPersistentStore - Model , Represents a single SQLite database on disk.
  • NSPersistentStoreCoordinator - Controller for any number of NSPersistentStore
  • NSManagedObjectContext - Model workspace , like a piece of Note Paper. Use and save or use and discard.

At this stage don't get tied up with UIManagedDocument . Its a controller for the file system with a CoreData stack on top. It doesn't do what you want to do out of the box.

Worry about the real problem which is how to load both the databases and use their data to drive your UI.

If its really important later you can move a UIManagedDocument based architecture. If this was my app I wouldn't bother.

0
On

If you go with UIManagedDocument see my github repo https://github.com/dtrotzjr/APManagedDocument - it might be useful, it might not. ;-)

4
On

I'm not even sure I would use one UIManagedDocument, let alone one for each user entry, for your app proposal. If your app design was intended to have multiple "books" of birds based on regions (as an example), then a UIManagedDocument would make sense per "book", but it sounds to me like you are making a single database of birds that will be built up over time, plus a "diary" that lists the user's entires (but are still part of the main bird database).

Your app sounds like a candidate for a straight forward Core Data based app. Your model design would have records of birds, plus a record representing the "diary" that relationally cross-references the "in-field user entries" of bird records. Even if you had multiple "diaries", UIManagedDocuments would seem to be overkill, and could be better served sticking with "simple" Core Data implementation.

Employ an NSFetchedResultsController to managed the interaction between Core Data and your UITableView for simplicity sake.

Merging multiple UIManagedDocuments would complicate your design considerably, in my opinion.