I am new to Core-Data so please help me with this.
i have this exception
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an entity named 'ModelForProfile' in this model.'
Although i searched almost all the answers available on internet and browsed the links available on stack but nothing seems to be understanding to me.
I have A few(5-7) different view's and a save button on each view.
1.) I am using Core-Data To save Data.MI doing right thing ??
2.) I need to have different Models for each View ??
3.) Initially i had an exception and when i browsed the web came to know that i need to change following method a bit
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"saveButtonForBasicInfo" withExtension:#"momd"];
//NSURL *modelURL1 = [[NSBundle mainBundle] URLForResource:#"saveButtonForProfile" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
// __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL1];
return __managedObjectModel;
}
Where " saveButtonForBasicInfo " is xcDataModel for the first model(First View).
and it worked perfect. But when this error occurred I tried adding a couple to more lines.
If you could see the commented lines.
Please Help me with this. As I am a bit confused .
Thank You,
Best Regards.
Some basic concepts:
You typically only have one NSManagedObjectModel in your app. It describes your entities (something like objects) and their attributes (something like properties).
This model is initialized at app launch, you should not have to revisit it. This usually happens in the AppDelegate setting up the "Core Data Stack" which also includes the NSManagedObjectContext and the NSManagedObjectStoreCoordinator.
Each of your views should use the NSManagedObjectContext to access the model and its data. Your suggestion that you need different models for different views is way off.
You should name your various things in a meaningful way. "saveButtonForBasicInfo" is not a meaningful name for a model. Call it something like "Widgets".
Similarly an entity should be something like "User", "Appointment", "Project", "Location", "Class", etc., i.e. something that represents something real. "ModelForProfile" is a very unsuitable entity name.
Related
I have a Core Data Database in my app using UIManagedDocument, and added a new version on top on an old one.
The new version works no problem if I'm adding new Entity without altering old Entity. But once I added a new attribute to an existing Entity of the old version. UIManagedDocument crashed at the point initWithFileURL was called. Here's how I created the UIManagedDocument.
UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:databaseURL];
self.databaseDocument = document;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
self.databaseDocument.persistentStoreOptions = options;
Seems like it crashed at modelByMergingModels called while initWithFileURL
I know this is the line of code that crashed because of the exception breakpoint.
If I delete the newly added attribute, create the NSManagedObject again. The code runs no problem again.
Any hints why is it failing? Any idea will be appreciated.
It is crashing because when it tries to create the document the options haven't been set yet. Create the document with just init, set its persistentStoreOptions then call configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:
Accepted answer from this question solved the problem.
UIManagedDocument migrate data model
- (NSManagedObjectModel *)managedObjectModel{
NSString *path = [[NSBundle mainBundle] pathForResource:#"Model" ofType:#"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
return managedObjectModel;
}
I don't really know why it has to be told about the file name of the NSManagedObjectModel. But looking into the stack at the point it crashed:
It really crashed at the call of UIManagedDocument's initWithFileURL calling of managedObjectModel. And deeper in the stack, it seems to be trying to merge all models that exist in the Bundle. Maybe, I guess that the two versions of the models are being treated as two models to be merged as one, instead of two versions - due to that the two versions appears to be two separate files in the Bundle. While trying to merge, the existence of two Tables w same Name but different attributes are causing conflicts, that's why it crashed.
Is it possible to serve two xcdatamodeld core data in the same project and load each according to a conditional?
I have BTPModel.xcdatamodeld and FTModel.xcdatamodeld
According to the comments this line below does this:
NSManagedObjectModel model = [NSManagedObjectModel mergedModelFromBundles:nil];
// looks up all models in the specified bundles and merges them; if
nil is specified as argument, uses the main bundle
Can I do something like this? (pseudo code)
if (config == #"FT") {
model = [NSManagedObjectModel load:#"FTModel.xcdatamodeld"];
} else {
model = [NSManagedObjectModel load:#"BPTModel.xcdatamodeld"];
}
UPDATE:
I have now tried this
NSURL *url = [[NSBundle mainBundle] URLForResource:#"F11iModel" withExtension:#"xcdatamodeld"];
Without any luck. url remains null.
UPDATE
Extension is momd. Now it works!
NSURL *url = [[NSBundle mainBundle] URLForResource:#"F11iModel" withExtension:#"momd"];
Of course you can. Just a few things to pay attention to:
The loading of a specific model is not done with some load method, but with initWithContentsOfURL. You get the URL with the main bundle's URLForResource. You can pass different resource names to this according to the configuration information.
I would recommend that you also use different persistent stores to make sure there is no attempt to open a the store with the wrong model (which will crash your app).
enter code hereI am working on an import tool, following the pattern objc.io did at https://github.com/objcio/issue-4-importing-and-fetching .
At an early point in the program, where I am creating an instance of NSManagedObjectModel from a url, it is returning nil. When I run the program, the error I get later is "Cannot create an NSPersistentStoreCoordinator with a nil model".
Attached is a screenshot at a breakpoint after I create the model. I've looked around here, and have verified that:
HistologyDataImporter.xcdatamodeld belongs to HistologyDataImporter (target membership)
The NSString I'm using the build the path matches the name of the model file ("HistologyDataImporter")
I have also tried passing "mom" as the extension to URLByAppendingPathComponent, but the model is still nil when run.
Why is [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] still returning nil?
Because you're using the wrong location. What you have is:
NSString *path = #"HistologyDataImporter";
NSURL *modelURL = [NSURL fileURLWithPath:path isDirectory:NO];
moelURL = [modelURL URLByAppendingPathComponent:#"momd"];
If you call fileURLWithPath: with a relative path like this, it's assumed to be relative to the current working directory. Your code does not set the working directory, but the value for modelURL suggests it's somewhere in Xcode's derived data folder. That's not surprising when running the app from Xcode, but the model file is not in that directory.
You need to figure out where HistologyDataImporter.momd is located and make sure that modelURL actually points to that location. If you put the model file on your desktop, you could use the same desktopURL that you have in main() and add the model filename to that.
I'm trying to create a NSSQLiteStoreType with the readonly option (NSReadOnlyPersistentStoreOption). This fails if the sqlite file doesn't exist (see code below). If it does exist, the store is added without any errors.
The error I get is Cocoa Error 260:
NSFileReadNoSuchFileError = 260, // Read error (no such file)
So it looks like CoreData tries to read a file that doesn't exist, instead of creating a new one...
It seems that when adding NSReadOnlyPersistentStoreOption you can only open a previously existing store, but not create one. This doesn't make sense to me.
Is there any way to create a brand new readonly store in Core Data?
If not, is there some workaround?
// DB URL
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *dbURL = [[fm URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
dbURL = [dbURL URLByAppendingPathComponent:#"store.sqlite"];
// Object Model
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
NSAssert([fm fileExistsAtPath:[modelURL path]], #"File not found");
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
// Store Coordinator
NSPersistentStoreCoordinator *coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// Add a readonly SQLite store
NSError *err = nil;
NSPersistentStore *store = [coord addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:dbURL
options:#{NSReadOnlyPersistentStoreOption : #YES}
error:&err];
if (store == nil) {
// I get a Cocoa Error 260.
NSLog(#"Error: %#", err);
}
Creating a new, empty, read-only store makes no sense, and the results you're seeing are exactly what would be expected. By specifying read-only you are specifically indicating that no file should be written, so as a result.... no file is written.
It's hard to tell what you're trying to accomplish. If the file were created, you would not be able to use it, since it would contain no data and since the read-only flag would prevent you from adding any data. An empty file would be exactly as useful.
But no, there is no way to tell Core Data to create a new persistent store file but have that file be read only, mainly because such an operation would be nonsensical and useless.
If you have some reason to want a persistent store file which is both empty and unwritable (and if you do, please share), you would need to
Add the persistent store without the read-only flag
Call removePersistentStore:error: to remove that persistent store
Add the persistent store again, with the read-only flag.
You will now have a persistent store which contains no data, and which you are prevented from adding data to.
A simpler alternative that is just as effective is to not create the file in the first place. An empty read-only persistent store serves literally no purpose at all, so the easy approach is to just not bother creating it.
I rearranged the files in my program folder, grouping them into appropriate subfolders. I made sure they all show up in the compiled sources list, including the 'xcdatamodeld' file.
However, creating a managed object model is not working with the following code:
if (mom_ != nil) {
return mom_;
}
self.mom = [NSManagedObjectModel mergedModelFromBundles:nil];
return mom_;
I examined [NSBundle mainBundle], and specifically
[[NSBundle mainBundle] pathForResource:#"Words" ofType:#"xcdatamodeld"]
and
[[NSBundle mainBundle] pathForResource:nil ofType:#"xcdatamodeld"]
They both return nil. I can see that other resources are there when I check for them by name and type.
There is a folder called "Words.momd" in the app bundle file.
What might have happened and how can it be fixed?
Try using:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Words" withExtension:#"momd"];
You want to load the compiled data model, vs. the xcdatamodeld file:
A data model is a deployment resource. In addition to details of the entities and properties in the model, a model you create in Xcode contains information about the diagram—its layout, colors of elements, and so on. This latter information is not needed at runtime. The model file is compiled using the model compiler, momc, to remove the extraneous information and make runtime loading of the resource as efficient as possible.
(source)
You can use MagicalRecords framework for it:
https://github.com/magicalpanda/MagicalRecord
and setup your db in one line of code:
[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:#"Words"];