2

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?

Odrakir
  • 4,254
  • 1
  • 20
  • 52

3 Answers3

3

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.

Warren Burton
  • 17,451
  • 3
  • 53
  • 73
  • This seems like a well thought out approach and you can use `UIManagedDocument` for the user data portion if you want to gain the benefits that `UIManagedDocument` brings to the table. – dtrotzjr Sep 13 '13 at 23:22
  • Great answer. So if I do what you say, but using UIManagedDocument, can I have both documents open (Diary and Bird's Database) at the same time? – Odrakir Sep 15 '13 at 09:27
  • 1
    check out this excellent tech blog too. In depth stuff including your general problem http://www.objc.io/issue-4/editorial.html – Warren Burton Sep 15 '13 at 18:19
0

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.

gschandler
  • 3,208
  • 16
  • 16
  • Ok, I was thinking in a UIManagedDocument because of the ease of deleting a diary entry and all its assets just with a few lines of code. – Odrakir Sep 13 '13 at 07:01
  • By the way, can I use iCloud to back up the diary without UIManagedDocument? – Odrakir Sep 13 '13 at 07:03
  • It is not much more complicated using Core Data directly to delete a diary entry. Yes, you can use Core Data with iCloud. – gschandler Sep 13 '13 at 17:55
  • I wouldn't say `UIManagedDocument` is overkill. You get full core-data support as well as some nice abstraction of some of the internals of core data that most developers should not care about in order to use the core data stack. – dtrotzjr Sep 13 '13 at 23:20
0

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

dtrotzjr
  • 928
  • 5
  • 18