views:

648

answers:

3

I am initializing a NSManagedObject subclass using:

- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues

I am also knowingly giving it the undefined keys, which of course should through an exception.

So, I have implemented:

- (void)setValue:(id)value forUndefinedKey:(NSString *)key

If a key is undefined, I map it to the correct key.

However, my implementation never gets called, instead NSManagedObject's implementation is used, which in turn still throws an exception.

Is there a behavior (or bug) that prevents setValuesForKeysWithDictionary: from using any NSManagedObject subclass implementation of setValue:forUndefinedKey:?

Adding code as requested, but since I am just implementing an existing method, which doesn't get called, I don't know how much help it will be:

In the context:

- (Company*)companyWithDictionary:(NSDictionary*)values{

    Company* newCompany = (Company*)[NSEntityDescription insertNewObjectForEntityForName:@"Company" inManagedObjectContext:self];

    [newCompany setValuesForKeysWithDictionary:values];

    return newCompany;
}

In the Company subclass (never called):

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{

    if([key isEqualToString:idKey]){

        [self setValue:value forKey:@"uniqueID"];

    }else if([key isEqualToString:descriptionKey]){

        [self setValue:value forKey:@"descriptionText"];

    }else if([key isEqualToString:timeUpdatedKey]){

        [self setValue:value forKey:@"dateUpdated"];

    }else{

        [super setValue:value forUndefinedKey:key];

    } 
}
+1  A: 

There's definitely nothing intrinsic to NSManagedObject that prevents this; I'm doing exactly this in the app I'm working on. Can you post more of your code?

One thought, also: are you sure it's setValue:forUndefinedKey: that's throwing the exception? For a managed object, I'm pretty sure you also need to implement valueForUndefinedKey: (the getter) to make things work properly.

Sixten Otto
Yes, I see it in the stack trace. And it is also definitely NSManagedObject's implementation.
Corey Floyd
I haven't implemented valueForUndefinedKey:. I will try that, but I don't see why that would through the setter out of whack.
Corey Floyd
Added some code…
Corey Floyd
My recollection, from when I was messing with this stuff a few days ago, is that something in the implementation of NSManagedObject seemed to be trying to check the current value of the property before setting the new one, and dying in the undefined getter. Once I implemented that, it got to the undefined setter as expected.
Sixten Otto
You are right. needed to implement the getter. Still getting a problem, but likely unrelated. Also, before I tried your solution, I just implemented setValuesForKeysWithDictionary: myself and it also worked fine. But because I am a masochist, I want to get it working this way!
Corey Floyd
+1  A: 

Simple question, but are you specifying your NSManagedObject subclass's class name for the entity in your model?

Also, you said you're initializing the managed object ... how? You should be inserting it via +[NSEntityDescription insertNewObjectForEntityForName: inManagedObjectContext:] in most cases, unless you have a good reason not to.

Joshua Nozzi
Yes and Yes. I also recreated my model classes to be sure. I also tried implementing valueFOrUndefinedKey in the model class AND as a category.
Corey Floyd
That is indeed strange. Can you reproduce this in a reduced test case? I've done similar things but never ran into this problem.
Joshua Nozzi
+1  A: 

A quick class-dump of the CoreData framework indicates that NSManagedObject also overrides setValuesForKeysWithDictionary:, so it looks like it definitely is doing some customization for that method, perhaps for performance reasons or something like that. I would probably just write my own method equivalent to setValuesForKeysWithDictionary: and call that instead to avoid the whole mess. Something like this:

- (void)mySetValuesForKeysWithDictionary:(NSDictionary*)dict
{
    for (NSString* key in dict)
        [self setValue:[dict objectForKey:key] forKey:key];
}
Brian Webster
thats essentially what I did, but accounting for NSNull values. Even after implementing Sixten's solution, there was some other strange error, so I have thrown in the towel.
Corey Floyd