Why does my NSManagedDataModel have no entities after I add another version of the DataModel? - nsmanagedobjectmodel

Why does my NSManagedDataModel have no entities after I add another version of the DataModel?
MacBook Pro Late 2008, OS X 10.8.5, Xcode 5.0.2,
Project has two apps, one OS X, one iOS, both share a datamodel
Recently add a new dataModel Version
DataModel involves four subClasses of NSManagedObject. Each of the four Classes received two identical changes, namely
the addition of two attributes:
modified NSDate
uid NSString
I did not select the option: Use scalar properties for primitive data types when generating
the files of the four classes.
When the following four lines execute in the OS X app,
NSString *path = [[NSBundle mainBundle] pathForResource:#"SqliteFromXml" ofType:#"momd"];
NSURL *momdURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momdURL];
NSLog(#"path=%#\nDataModel=%#\nEntities in DM=%#",path,managedObjectModel,[managedObjectModel entities]);
This is the output:
path=/Users/appleuser/SqliteFromXml/Debug/SqliteFromXml.app/Contents/Resources/SqliteFromXml.momd
DataModel=(<NSManagedObjectModel: 0x1001d1b80>) isEditable 0, entities {
}, fetch request templates {
}
Entities in DM=( )
The momd bundle is being created on each run, but is has 0 entities.
The .app bundle Contents looks this way:
https://www.dropbox.com/s/68iy8gjqbv0m0tq/Screenshot%202014-02-16%2018.03.02.png
Many Thanks, Mark

Datamodel bundle name: IHM_Recipes.xcdatamodeld (developed as part of the original iOS app)
There are two products both sharing a common datamodel:
iHungryMePlus (iOS)
SqliteFromXml (Mac)
There was a user error in my choice of param for pathForResource: for the first line of code below:
NSString *path = [[NSBundle mainBundle] pathForResource:#"IHM_Recipes" ofType:#"momd"];
NSURL *momdURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momdURL];
I used pathForResourceParam == #"SqliteFromXml". Sorry to waste your time. Because a momd file named SqliteFromXml.momd was created, I wrongly concluded that pathForResourceParam was
used for targeting rather than searching. I see now this was very bad logic. This approach to create a MOM came from Jeff Lamarche.

Related

Get name of Xcode Project in actual code

So you know the part of the project that is "MyNameGoesHere.app" or "MyNameGoesHere.xcodeproj" - is there a way to get the MyNameGoesHere part via objective-c code?
I can get all kind of device info from UIDevice messages but I can't figure out how to get project/app name.
CFBundleDisplayName doesn't work anymore. Use:
NSString *bundleName = [[NSBundle mainBundle]
objectForInfoDictionaryKey:#"CFBundleName"];
You're probably looking at the bundle's InfoDictionary. You can get the app's name via the following code:
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
NSString *bundleName = [NSString stringWithFormat:#"%#", [info objectForKey:#"CFBundleDisplayName"]];

How can I get relative path of the folder in my project ?(iPhone)

Suppose, I have added one folder name "Images" in my project.How can I get the path to that folder? My main intention is to get the number of pictures in "Images" folder.
You should work a bit more on your question: it assumes a lot and requires the reader to guess.
I have added one folder name "Images" in my project
So I guess this means you added it as a folder reference
and I want to get it's path
And I guess that you want to do that at run time from your application, not at build-time from Xcode.
If so, you could do something like:
NSURL *containingURL = [[NSBundle mainBundle] resourceURL];
NSURL *imageURL = [containingURL URLByAppendingPathComponent:#"Images" isDirectory:YES];
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSArray *content = [localFileManager contentsOfDirectoryAtURL:imageURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants error:NULL];
[localFileManager release];
NSUInteger imageCount = [content count];
This code does not assume that all images are of the same kind.
[[[NSBundle mainBundle] pathsForResourcesOfType:#"jpg" inDirectory:#"Images"] count];
This returns the number of jpg images from the Images folder. This is the case if you added the images to your application bundle.

'-[NSURL initFileURLWithPath:]: nil string parameter' when using CoreData

I have some model classes which I wanted to store with the CoreData framework. I have created the xcdatamodel file and added these already existing classes to the CoreData model file. I have also copied the code responsible for managing the context, etc. from the core data project template from the XCode.
Now I have the following code (it was copied, only the file name was changed to HistoryDataModel):
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:#"HistoryDataModel" ofType:#"momd"];
NSLog(#"Model path:", modelPath);
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
}
Now when I run this code and try to access data in the CoreData I'm getting the following error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSURL initFileURLWithPath:]: nil string parameter'
and it happens when
NSString *modelPath = [[NSBundle mainBundle] pathForResource:#"HistoryDataModel" ofType:#"momd"];
is being executed (the model Path is an empty string).
Any ideas what I might have done wrong?
Thanks!
You could try the following snippet, which will save you a lot of time :)
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
It returns a model created by merging all the models found in all the bundles (nil parameter). You can set the parameter to a specific array of bundles.
Is your core data model versioned already? If not then the correct extension should be mom
To create a versioned model you select the model and run Design/Data Model/Add Model Version in the menu.
I just had the same issue and here is how I resolved it:
Here is my old code
[self.PDFWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:pdfFileName ofType:#"pdf"]]]];
Here is my resolved code:
[self.PDFWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath: [[NSBundle mainBundle]pathForResource:pdfFileName ofType:#"PDF"]]]];
As you can see, the first line has ofType:#"pdf" while the second has ofType:#"pdf". All my pdf files included in the app ended in .PDF, so I was getting a nil error when I was looking for file type pdf.
Obvious error, but I thought IOS would be smart enough to check for both .pdf and .PDF, but I was wrong. Perhaps that is the issue this person was having.

Core Data migration "can't merge models with two different entities named 'foo'"

I know this is a frequently asked question, however none of the solutions that I have found seem to work for me.
This is my situation:
I have one data model for my application, and I wanted to add versioning to it. So in XCode, I did Design -> Data Model -> Add Model Version. I also updated my delegate's persistentStoreCoordinator method to look like this:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"foo.sqlite"]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
/*Error for store creation should be handled in here*/
}
return persistentStoreCoordinator;
}
Just to make sure everything was still working, I did a clean all, build, and tested it in the simulator. Everything worked so far.
Next I chose the new version data model, set it to be the current version using XCode, and added one extra attribute to an entity. I then did a clean all, build. And now whenever I start the application it crashes with this error: 'Can't merge models with two different entities named 'foo''.
What am I doing wrong? I have tried making sure that no data model is added to the target, adding just the current version data model to the target, and both. Every time I test I make sure to clean all.
Can anyone shed some light as to why it does not work for me?
EDIT:
here is my managedObjectModel method:
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
return managedObjectModel;
}
I already expected this implementation of the managedObjectModel getter.
In your implementation all models within the bundle are merged into one single model. Therefore also all versions within the .momd are merged resulting in duplicate entity definitions.
Change the code to explicitly initialize the model with the apropriate model file and it should work fine.
NSString *modelPath = [[NSBundle mainBundle] pathForResource:#"datamodel" ofType:#"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
If you're using Version Models on Core Data you always have to initialize to the version of the model that you want to use. On the Application Bundle you will find one file with extension .momd that is the Full Model. Inside of this file you will find a lot of .mom files inside, each .mom file represent one version of your model.
If you run your application and initialize with the .momd file and all versions inside, Core Data will create all versions and later we will have the "duplicated entity" error, Core Data don't known what version use. Now, the only way to fix the problem is delete the app, point your code to the correct .mom file and run again, so Core Data create only one version of the internal database.
Here's one snippet of code that do the job:
NSString *fullModelName = #"myModel.momd"; // The name of the main model.
NSString *modelVersionName = #"myModel1.0.mom"; // Only the name of the version.
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *modelPath = [NSString stringWithFormat:#"%#/%#/%#", bundlePath, fullModelName, modelVersionName];
//
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

Error Building Core Data Stack in Unit Tests

I am trying to get started with unit testing an app that uses Core Data. In the setUp method of my unit first test, I can get the path to my data model but for some reason cannot convert it to a NSURL.
My setUp method is:
- (void)setUp {
NSBundle *bundle = [NSBundle bundleWithIdentifier:#"com.testcompany.LogicTests"];
STAssertNotNil(bundle, #"Error finding bundle to create Core Data stack.");
NSString *path = [bundle pathForResource:#"DataModel" ofType:#"momd"];
STAssertNotNil(path, #"The path to the resource cannot be nil.");
NSURL *modelURL = [NSURL URLWithString:path];
STAssertNotNil(modelURL, #"The URL to the resource cannot be nil. (tried to use path:%#, modelURL is %#)", path, modelURL);
...
}
The error I'm getting is:
/Users/neall/iPhone Apps/TestApp/UnitLogicTests.m:24:0 "((modelURL) != nil)" should be true. The URL to the resource cannot be nil. (tried to use path:/Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd, modelURL is (null))
I've checked the filesystem and the directory /Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd exists.
What am I missing here?
Thanks!
Try using [NSURL fileURLWithPath:path] instead to construct the url
Double check that you are seeing a directory called DataModel.momd at /Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd.
If you added a xcdatamodel file by the Add New File... command in Xcode, you would only have one file and it would be DataModel.mom (no trailing d). If that's the case, changing the
NSString *path = [bundle pathForResource:#"DataModel" ofType:#"momd"];
to
NSString *path = [bundle pathForResource:#"DataModel" ofType:#"mom"];
will fix your immediate issue.
You want to use the fileURLWithPath: that Claus suggested as well.
If you want to do versioning of your model in the future and you currently have only a .mom file, select your DataModel.xcdatamodel file in XCode and go to Design -> Data Model -> Add Model Version. This will force the creation of the DataModel.momd directory with the DataModel.mom file in it. You can just delete the new version it adds into that directory and your original tests will work.
xcdatamodel should also be added to
Project -> Targets -> "unit test target" -> build phases -> compile sources
After spending several hours stacking in July 2014 this post was one of several that in part led me to the working solution.
We somehow managed to break the surprisingly fragile (and mysterious) mechanism that links the bundle that your source code lives in to the bundle that runs the unit test. Further you might have a misnamed xcdatamodel. See comments for explanations:
-(NSManagedObjectContext *) getManagedObjectContext
{
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
//Replace MyClass with class that is from your data model
//really any of your classes should work
NSBundle * bundle = [NSBundle bundleForClass:[MyClass class]];
//You can uses this line to figure you what your bundle is actually named
//In my case the because my PRODUCT_NAME had spaces in it they was replaced with '-'
//(dashes) and I couldn't divine it from the info.plist and the Build Settings.
NSString * ident =[bundle bundleIdentifier];
//This will show you where your app is actually out building temporary files
//The exact location appears to change every version or to of Xcode so
//this is useful for figuring out what your model is named
NSString * bundlePath =[bundle bundlePath];
//Here replace Name_of_model_without_the_dot_xcdatamodel with the name of your
//xcdatamodel file without an extension
//Some tutorials will have you use AppName.xcdatamodel others will simply name it
//DataModel.xcdatamodel.
//In any event if bothe path and path1 return null then check the
//bundlePath by going to Finder and pressing Command-Shift-G and pasting
//bundlePath into the pop-up. Look around for a mom or momd file thats the name you want!
NSString* path = [bundle
pathForResource:#"Name_of_model_without_the_dot_xcdatamodel"
ofType:#"momd"];
//If the above 'path' and 'path1' is not then you want to use this line instead
NSString* path1 = [bundle
pathForResource:#"Name_of_model_without the_dot_xcdatamodel"
ofType:#"mom"];
//the above path lines are simply so you can trace if you have a mom or a momd file
//replace here appropriately
NSURL *modelURL = [bundle URLForResource:#"Name_of_model_without the_dot_xcdatamodel"
withExtension:#"momd"];
//the rest is boiler plate:
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSPersistentStoreCoordinator *psc =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
[psc addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil URL:nil options:nil error:nil];
[moc setPersistentStoreCoordinator:psc];
return moc;
}
Here is how you might use the above context:
-(void)testMyStuff
{
NSManagedObjectContext* context=[self getManagedObjectContext];
MyClass *myobj=[NSEntityDescription insertNewObjectForEntityForName:#"MyClass"
inManagedObjectContext:context];
}
One final note you may also have to add your source files and xcmodel under the "Compile Sources" of build phases. This unfortunately changes with almost every version of Xcode. For Xcode 5: