can't find managed object model? - objective-c

I created a entity called photo inmy .xcdatamodel.
but when I tried to add it into my context:
NSManagedObjectContext *context = [self managedObjectContext];
Photo *p = [NSEntityDescription insertNewObjectForEntityForName:#"Photo" inManagedObjectContext:context];
it had run-time error:
+entityForName: could not locate an NSManagedObjectModel for entity name
'Photo'
it's really weird, I included the Photo.h, generated by xcode coredata.
does anyone have an idea why it goes wrong?
I can't find what's wrong at all.. > <
Thanks!

Make sure your call to [self managedObjectContext] is returning a valid context (and not nil). Also make sure you're using the proper case (you said your entity was called "photo" but you're trying to insert a new object for an entity named "Photo").

Related

CoreData: error: Failed to call designated initializer on NSManagedObject class

I have a little damn problem with CoreData. I want to insert a new Object, so I first have to create one. This is done by that code:
Challenges *newChallenge = [[Challenges alloc] init];
[newChallenge setName:#"TestChallenge"];
[newChallenge setRounds:[[NSNumber alloc] initWithInt:12]];
[newChallenge setShots:[[NSNumber alloc] initWithInt:5]];
[newChallenge setDate:[NSDate date]];
But however after the alloc init I get this error:
CoreData: error: Failed to call designated initializer on NSManagedObject class 'Challenges'
What the hack is going wrong?
I think the problem is that Challenges is a NSManagedObject class and you need the designated initializer:
initWithEntity:insertIntoManagedObjectContext:
instead of
Challenges *newChallenge = [[Challenges alloc] init];
Read More..
In case you ask yourself "OK, so how to I get that entity?" (like I did), you do this by using the entityForName method like so:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Challenges" inManagedObjectContext:self.managedObjectContext];
Challenges *newChallenge = [[Challenge alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
Hope this helps, this thread has helped me a lot!
NSManagedObject cannot be just alloc/init like you would normally do with an NSObject. As a matter of fact the designated initializer is:
initWithEntity:insertIntoManagedObjectContext:
Now, for the actual error, Apple states in the documentation that:
Important: This method is the designated initializer for
NSManagedObject. You must not initialize a managed object simply by
sending it init.
So, you could see that you need 2 things in order to initialize it, an NSEntityDescription (which entity you intend to instantiate) and an NSManagedObjectContext (the context that the new object will be created into).
Others have already stated why its not working. Here is how you can cut down on the boilerplate and make your code more readable:
#implementation NSManagedObject(MyPrivateAdditions)
+ (id)insertNewObjectInContext:(NSManagedObjectContext *)context
{
return [NSEntityDescription insertNewObjectForEntityForName:self.className inManagedObjectContext:context];
}
#end
now you can do:
Challenges *newChallenge = [Challenge insertNewObjectInContext:context];
Additionaly, if your Challenges class is NSManagedObject and date, rounds and shots are defined as its attributes you can add method:
-(void) awakeFromInsert {
self.date = [NSDate date];
self.rounds = #(12);
self.shots = #(5);
}
Each new object will have defined those attributes from its birth.

NSManagedObject Entity Inheritance causes NSInternalInconsistencyException

I have an NSManagedObject ElementA with several attributes that should exist in ElementB through a parent-child relationship. When setting ElementA as the Parent Entity to ElementB, the NSPersistentStoreCoordinator fails. The ManagedObjectModel is correctly being built, and the entities/classes work separate of each other. The only difference between the app failing and compiling is this parent-child relationship. None of the attributes from either entity overlap.
I don't have enough rep yet, so the images are at the following links: ElementA Model, ElementB Model.
As far as troubleshooting goes, I've tried all of the following:
With and without implementing custom classes.
Setting ElementA as abstract (however I need it to not be abstract)
Removing and then adding in the attributes one at a time (including emptying all attributes of both entities)
Resetting Xcode (clean), the simulator (reset all), and restarting my machine.
I've read up on Apple's Docs (Core Data Programming Guide: Managed Object Models) and everything seems to align with their guidelines for Entity Inheritance.
This is the line that fails:
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
What do I seem to be missing here? It's got to be obvious as this does not seem like it should be this hard. Any and all help is appreciated!
Edit for #Rog's Comment
The application fails as soon as the core data model is accessed for the first time at startup. The new images above show that I am trying to set the Parent Entity of ElementB using the Model Editor. The following is the error message I'm receiving:
uncaught exception 'NSInternalInconsistencyException', reason: 'Bad model. For entity 'ElementA' subentity 'ElementB (0x785d790)' is not registered in NSManagedModelModel. Model has a reference to ElementB (0x785e320)'
Not the full code... but this is how I achieved what #Scott BonAmi is talking about when removing the temporary entities. As I'm still using modelByMergingModels:, it figures out the sub entities itself.
NSMutableArray *finalModels = [NSMutableArray arrayWithCapacity:0];
NSMutableArray *updatedEntities = [NSMutableArray arrayWithCapacity:0];
for (NSManagedObjectModel *immutableModel in allModels) {
NSManagedObjectModel *model = [immutableModel mutableCopy];
for (NSEntityDescription *entity in [model entities]) {
if ([[[entity userInfo] objectForKey:#"TempPlaceholder"] boolValue]) {
// Ignore placeholder.
DULog(#"Ignoring: %#", entity.name);
} else {
[updatedEntities addObject:entity];
}
}
[model setEntities:updatedEntities];
[updatedEntities removeAllObjects];
[finalModels addObject:model];
}
NSManagedObjectModel *model = [NSManagedObjectModel modelByMergingModels:finalModels];
Ended up being a logic error with code I used from another SO answer creating the MOM dynamically.
When adding entities to the array during the looping sequence, ElementB (0x785d790) is added as a subentity of ElementA, and then later in the loop 'ElementB (0x785e320)' is added, thus causing different memory locations and throwing an NSInternalInconsistencyException.

Objective C: Request for member XXX in something not a structure or union. (Core Data)

I am hitting this error when implementing core data.
I have created a entity 'FlashCard' with the attribute 'question' and 'answer'. Both the attributes are of NSString type.
After inserting a new object into the NSManaged Object, I tried to set the 2 attributes as seen below.
NSManagedObject *newCard = [NSEntityDescription insertNewObjectForEntityForName:#"FlashCard" inManagedObjectContext:self.managedObjectContext];
newCard.question = thisQuestion;
newCard.answer = thisAnswer;
But when I try to compile the code, I am hitting the error "Request for member 'question' in something is not a structure or union'. I get the same error for newCard.answer line.
Any advise on how to resolve this is greatly appreciated!
Zhen
Your newCard instance should be of type FlashCard not NSManagedObject; otherwise, the compiler won't know that newCard has the properties question and answer.
FlashCard *newCard = (FlashCard *)[NSEntityDescription insertNewObjectForEntityForName:#"FlashCard" inManagedObjectContext:self.managedObjectContext];
newCard.question = thisQuestion;
newCard.answer = thisAnswer;
You've declared newCard as an NSManagedObject, then tried to access properties that NSManagedObject doesn't define.
Core Data gives you the option of using a custom subclass of NSManagedObject to represent entities. If you're doing this then, as others have suggested, you need to declare newCard as an instance of that subclass (in case you're not doing this, you'll have to write the class and declare the properties yourself if you want to use the 'dot' property syntax --- core data doesn't automatically create a subclass of NSManagedObject for each entity type)
Also, you don't have to use your own subclass or write accessors just to access a managed object's attributes and relationships. If you don't need to add any custom logic to FlashCard yet, you can use key value coding on an NSManagedObject instead. This would work fine:
NSManagedObject *newCard = [NSEntityDescription insertNewObjectForEntityForName:#"FlashCard" inManagedObjectContext:self.managedObjectContext];
[newCard setValue: thisQuestion forKey: #"question"];
[newCard setValue: thisAnswer forKey: #"answer"];
#import "FlashCard.h"
Is "FlashCard.h" included at the top of this file?

CoreData issue with appDelegate

I'm relatively new to Objective C. So far everything has been going really well until I hit CoreData. I just can't get it to work! After spending many hours on something that seems to be pretty straightforward, I'm at my wits' end.
PLEASE help me figure out what I have done wrong:
I created a new Windows-Based app and checked 'use Core Data for storage'
In the xcdatamodel, I created an entity named 'RecipeData' with only one attribute 'recipeName' it is a string
in the app delegate, I load an XML file and parse it. When I parse the recipe name, I use the following:
recipeData *dataName = (recipeData *) [NSEntityDescription insertNewObjectForEntityForName:#"RecipeData" inManagedObjectContext:managedObjectContext];
I get the following error:
terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'RecipeData'
Which leads me to the big 3 questions:
is there anything really obvious that I am doing wrong?
since I checked 'use Core Data for storage,' it seems the following code is injected automatically into the app delegate .h:
#private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
Does this interfere with the code I am using?
I tried creating a new NSManagedObjectContext called *myManagedObjectContext but that did not work.
One other tidbit, when I add the following right above my code:
if (managedObjectContext == nil) {
NSLog(#"NO CONTEXT");
}
The console prints "NO CONTEXT"
I really appreciate any help. Thanks.
Where has managedObjectContext come from? Is it a typo for managedObjectContext_? The project templates create the latter, not the former. Using the code above with the code provided by the standard project templates should produce a syntax error. I'm guessing you've renamed some things?
You seem to be using managedObjectContext as an ivar. It is a property. Inside the class, there is a private managedObjectContext_ ivar which holds the reference to the object context. You shouldn't access this. You should be accessing the managedObjectContext property. When this property is first accessed, its getter method will create the context for you. Since you aren't accessing the property, the getter method isn't called and the context never gets created.
Where you have code like this:
recipeData *dataName = (recipeData *) [NSEntityDescription insertNewObjectForEntityForName:#"RecipeData" inManagedObjectContext:managedObjectContext];
...you should be using code like this:
recipeData *dataName = (recipeData *) [NSEntityDescription insertNewObjectForEntityForName:#"RecipeData" inManagedObjectContext:self.managedObjectContext];
Note the self. bit. This means that you are accessing a property on the self object, not accessing an ivar from the object the method is being called on.
Note that reading a property is the same as calling the getter method, so the above can also be written as:
recipeData *dataName = (recipeData *) [NSEntityDescription insertNewObjectForEntityForName:#"RecipeData" inManagedObjectContext:[self managedObjectContext]];

Customized initializers and read only properties in Core Data

Before working with Objective-C and Core Data, I had occasions to create classes that needed to be initialized with certain parameters that, after initialization, could not be modified (though they could be read).
With Core Data, I believe I can create a customized init on my NSManagedObject derived class as long as it includes a way to insert the object into a context like such:
-(Cell*) initWithOwner:(CellList*)ownerCellList andLocation:(int)initLocation
{
if (self = (Cell*) [NSEntityDescription insertNewObjectForEntityForName:#"Cell"
inManagedObjectContext:[ownerCellList managedObjectContext]])
{
self.location = [NSNumber numberWithInt:initLocation];
self.owner = ownerCellList;
[ownerCellList addCellListObject:self];
}
return self;
}
Normally, I'd have a location variable and the location property would be read-only (so once set at initialization, it could not be changed). Is there a way to get this sort of pattern with Core Data? Is there a better way I'm not thinking of?
Thanks!
You are correct. As long as your initializer calls the NSManagedObject's designated initializer, your approach is fine. You can also override the -[NSManagedObject awakeFromInsert] to perform some action after insertion (creation) or -[NSManagedObject awakeFromFetch] to perform an action (e.g. populating a cache) each time the object is faulted back into a managed object context.
Like the rest of Objective-C, there is no way to make a property truly readonly. Malicious code will likely be able to modify your property. However, in your custom class, you can declare a #property(readonly) for e.g. location. This will at least cause a warning if you try to modify the property and will signal your intent to client code.
For anyone who stumbles here, reads the comments, and wonders at the final answer, it should be something like this. Continuing with the example above, it would be:
-(Cell*) initWithOwner:(CellList*)ownerCellList andLocation:(int)initLocation
{
NSManagedObjectContext *context = [ownerCellList managedObjectContext];
NSManagedObjectModel *managedObjectModel =
[[context persistentStoreCoordinator] managedObjectModel];
NSEntityDescription *entity =
[[managedObjectModel entitiesByName] objectForKey:#"Cell"];
self = [self initWithEntity:entity inManagedObjectContext:context];
if (self)
{
self.location = [NSNumber numberWithInt:initLocation];
self.owner = ownerCellList;
[ownerCellList addCellListObject:self];
}
return self;
}
NSEntityDescription's insertNewObjectForEntityForName:inManagedObjectContext: documentation says this is roughly how it converts from a given entityName (#"Cell") and a context (from ownerCellList) to an NSManagedObject instance.