Re: Core Data Merged Models
Re: Core Data Merged Models
- Subject: Re: Core Data Merged Models
- From: Matthew Firlik <email@hidden>
- Date: Sat, 22 Apr 2006 13:11:27 -0700
On Apr 22, 2006, at 2:13 AM, Jonathon Mah wrote:
The template code for a "Cocoa Core Data Application" creates a
managed object model with the following code:
NSMutableSet *allBundles = [[NSMutableSet alloc] init];
[allBundles addObject:[NSBundle mainBundle]];
[allBundles addObjectsFromArray:[NSBundle allFrameworks]];
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:
[allBundles allObjects]] retain];
What is the purpose of merging models contained in frameworks? In
other words, what advantage does this have over
[[NSManagedObjectModel alloc] initWithURL:myMomURL] (apart from not
needing to know the URL)?
The code is a small convenience to allow the template to work out-of-
the-box (meaning, almost immediate turn-around) for those who are
developing (just) an application or an application and framework
(where the framework contains models as well.) The code to write to
load a single model from its URL isn't complicated, though you do need
to know the bundle it resides in (exploded here for clarity):
NSBundle *bundle = [NSBundle mainBundle]; /// or some other API ...
NSString *modelPath = [bundle pathForResource: @"MyModel"
ofType:@"mom"];
NSURL *modelURL = [NSURL fileURLWithPath: modelPath];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc]
initWithContentsOfURL: modelURL]
Obviously if you have more than one model (and you plan to use them in
concert), you need to have them merged before adding them to the
coordinator. You can do that with the convenience API, or yourself
using:
NSArray *models = [NSArray arrayWithObjects: model1, model2, /*(etc)
*/ nil];
NSManagedObjectModel *mergedModel = [NSManagedObjectModel
modelByMergingModels: models];
Which isn't all that difficult, but since you have to locate the
bundles for the models anyway to get the URL information, it's just as
simple toss the bundles to the mergedModelsFromBundles: API and have
it done for you. By the way, the code:
NSManagedObjectModel *model = [NSManagedObjectModel
mergedModelFromBundles: nil];
defaults to loading all models from the main bundle ([NSBundle
mainBundle]).
If the user added a framework to the system which contained its own
MOM, could that render existing stores unreadable by apps using this
code?
This is an important thing to think through. It can be dangerous to
load models from all linked frameworks/bundles if you are unsure if
they have models in them, or what the models actually contain. For
example, in cases where separate developers haven't clearly (meaning,
uniquely) named their entities, the merging API would complain about
having conflicting entity descriptions when it went to merge.
(Perhaps a little known fact, but Core Data will ignore an attempt to
load the *exact same* entity more than once -- so if you tried to
merge a model with itself, Core Data wouldn't be bothered.)
However, the true danger here is when using the SQL stores. When you
create a SQL store with a model, Core Data will create tables for ALL
entities in the specified model (even if you use a configuration,
because the store must be able to support the model even if you change
configurations to another collection of entities.) Thus, if you are
(unaware that you are) loading models from frameworks, you'll have
more tables in your store than you expected. That's not a problem in
itself ... *unless* those models happen to change! If they did
(including if the model goes away), then the merged model for your
application would be different than before, and incompatible with any
stores you created with the previous merge.
In summary -- the merged-models API is convenient and safe in
situations where you own or are 100% certain of the content and
stability of the bundles you are passing to it. For most developers,
that probably means (just) passing their bundles or nil to get the
correct resulting model. If you want to protect against accidentally
loading other models, then the initWithContentsOfURL: method it your
best bet. (As an aside, we've already changed the Xcode templates for
the next major release to use the URL-based methods: as more
frameworks add models, this will make loading more than one model a
very conscious decision.)
Finally -- for all framework developers -- if you are worried about
this case (where someone might accidentally load your model), or you
are concerned about those who might explicitly load your model
(because they see a resource with the .mom extension) to "troll" your
data content without using your API, you might consider adding a shell-
script build phase in Xcode to change the extension of your compiled
model file to something other than ".mom." Doing so would mean the
merged models API wouldn't "see" the model(s) (since it looks for
resources with the ".mom" extension), thus making them accidental-load
proof: it does mean any explicit consumers have to use the
initWithContentsOfURL: method to load the model (or, go through API
you provide), but it might be a good thing.
- matthew
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden