timothyjosefik
timothyjosefik

Reputation: 126

Core Data NSString works NSNumber does not

I'm developing an app on iOS in Objective-C.
I'm trying to use Core Data but I'm getting a really weird issue.

@interface Food : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * bought;
@property (nonatomic, retain) NSNumber * quantity;

@end

/

- (void)viewDidLoad {
[super viewDidLoad];
Food* newFood = (Food*)[NSEntityDescription entityForName:@"Food"
                                   inManagedObjectContext:self.managedObjectContext];
NSLog(@"%@", newFood.name);
NSLog(@"%d", [newFood.quantity intValue]);

This will print the name, but will give me an error on the quantity.
I have tried many different things and I don't know what the problem is.
I did not change the data model or do anything different in between the string and the number.
I even remade everything in a new project and same thing.

Here is the error :

2015-06-22 13:05:22.219 Test[50408:2682580] Food
2015-06-22 13:05:22.219 Test[50408:2682580] -[NSEntityDescription         quantity]: unrecognized selector sent to instance 0x7fdb7ae24a60
2015-06-22 13:05:22.221 Test[50408:2682580] *** Terminating app     due to uncaught exception 'NSInvalidArgumentException', reason: '-    [NSEntityDescription quantity]: unrecognized selector sent to instance 0x7fdb7ae24a60'

Upvotes: 0

Views: 105

Answers (2)

vikingosegundo
vikingosegundo

Reputation: 52237

You are creating a NSEntityDescription instance, that just describes (hence the name) an entity. But instead of using it, you brutally cast that to the desired Class, but casting only tells the compiler to shut up, it does not magically convert something into anything else.

NSEntityDescription happens to have a name attribute, that is why that line works.

try

Food *newFood = [NSEntityDescription insertNewObjectForEntityForName:@"Food" 
                                              inManagedObjectContext:self.managedObjectContext];

From the Core Data Programming Guide

  • The Entity Description

    An entity description specifies (amongst other things) the name of an entity, the class used to represent the entity, and the entity’s properties. The entity description is important since a given class may be used to represent more than one entity—by default all entities are represented by NSManagedObject. Core Data uses the entity description to determine what properties a managed object has, what needs to be saved to or retrieved from the persistent store, and what constraints there are on property values. Entity descriptions are properties of a managed object model.

  • Creating a Managed Object

    Fundamentally NSManagedObject is an Objective-C class like any other Objective-C class. Like various other classes, NSManagedObject imposes some constraints on instance creation. As described earlier, you must associate the new managed object instance with the entity object that defines its properties and with the managed object context that defines its environment. You cannot therefore initialize a managed object simply by sending an init message, you must use the designated initializer — initWithEntity:insertIntoManagedObjectContext:—which sets both the entity and context:

    NSManagedObject *newEmployee = [[NSManagedObject alloc] initWithEntity:employeeEntity
                                             insertIntoManagedObjectContext:context];
    

Some more observations:

  • Nowadays I expect Objective-C/Cocoa(-touch) code to be using Automatic Reference Counting, in that the retain attribute for properties should be exchanged with strong

  • for NSString properties you almost certainly want copy instead of strong


  • Does this automatically save when using the insertNewObject?

No, as this could lead to not fully populated object in the store depending on your model & app logic.

  • or would have still have to call saveContext from the delegate?

Where and when to save depends on your app logic.

Upvotes: 1

Jeff
Jeff

Reputation: 4229

You are not getting back an NSManagedObject subclass Food, you are getting an NSEntityDescription.

You don't want entityForName:inManagedObjectContext: you want insertNewObjectForEntityForName:inManagedObjectContext:.

Explanation of your odd debug info:

The reason the name property works is because that is a property of NSEntityDescription. Change your Food property to foodName and watch what happens. The name call will still work.

Upvotes: 1

Related Questions