4

I need to check if an NSEntityDescription key exists before trying to set the value. I have a dictionary of data from JSON and don't want to try setting keys that do not exist in my object.

Appointment *appointmentObject = [NSEntityDescription insertNewObjectForEntityForName:@"Appointments" inManagedObjectContext:[[DataManager sharedInstance] managedObjectContext]];
for (id key in dict) {
    // Check if the key exists here before setting the value so we don't error out.
        [appointmentObject setValue:[dict objectForKey:key] forKey:key];
}
Bot
  • 11,868
  • 11
  • 75
  • 131

3 Answers3

12

you should not check for selectors. Imagine a key called entity or managedObjectContext. The NSManagedObject class definitely responds to those selectors, but the best thing that will happen if you try to assign something wrong to those is that your code crashes instantly. A little less luck and something like this destroys the complete core data file, and all the user data.

NSEntityDescription has a method named attributesByName which returns a dictionary with your attribute names and corresponding NSAttributeDescriptions. So these keys are basically all the attributes you can use.

Something like this should work:

Appointment *appointmentObject = [NSEntityDescription insertNewObjectForEntityForName:@"Appointments" inManagedObjectContext:[[DataManager sharedInstance] managedObjectContext]];
NSArray *availableKeys = [[appointmentObject.entity attributesByName] allKeys];
for (id key in dict) {
    if ([availableKeys containsObject:key]) {
        // Check if the key exists here before setting the value so we don't error out.
        [appointmentObject setValue:[dict objectForKey:key] forKey:key];
    }
}
Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
  • You make a very good point! Since I am relying on a JSON response to provide the keys, it is VERY possible for them to have keys that respond to normal selectors. – Bot Mar 13 '12 at 20:52
6

Check this,

BOOL hasFoo = [[myObject.entity propertiesByName] objectForKey:@"foo"] != nil;

Bot
  • 11,868
  • 11
  • 75
  • 131
Arun
  • 476
  • 4
  • 6
-1

I think you are asking that you want to check if the appointmentObject responds to a property. In that case:

if([appointmentObject respondsToSelector:NSSelectorFromString(key)])...

The getter equivalent is propertyName. The setter equivalent is setPropertyName.

Gobot
  • 2,464
  • 1
  • 21
  • 26
  • is this the same as `respondsToSelector:@selector(key)`? If so I tried that and it didn't work. – Bot Mar 13 '12 at 20:09
  • is the key a string or another type of object? I assumed it was a string. – Gobot Mar 13 '12 at 20:12
  • all `@property` are `NSString` except for one which is `NSNumber`, however the error is when it encounters a key that is not in the `Appointment` class. – Bot Mar 13 '12 at 20:19
  • -1 because checking for selectors is not save for something like this. You could set the `managedObjectContext`, or the `entity` with this code. And because you just check for the getter you could even set the `description` of the class. At least the app would try to set them, and crash when it actually does. – Matthias Bauch Mar 13 '12 at 20:49