Looks KVC-compliant to me, but Cocoa says it ain't

  • In order to implement the solution that mmalc gave me last week to my
    Core Data swimming-meet problem in a demo project, I've written a
    category on NSMutableSet, which has gotten me into one of those
    arguments with the Cocoa runtime as to whether or not a class is KVC
    compliant.  As usual, being more stubborn than I, Cocoa is winning...

    This code:

    // glueClass is a variable of type Class, value is class 'Entry'
    id glueObject = [[glueClass alloc] init] ;
    NSNumber* position = [[NSNumber alloc] initWithInt:i] ;
    // The following sanity test is for debugging...
    if (
            [glueObject respondsToSelector:@selector(position)]
          && [glueObject respondsToSelector:@selector(setPosition:)]
        ) {
            NSLog(@"%@ responds to setter and getter, looks good!!",
    glueClass) ;
    }
    // Now, the trouble...
    [glueObject setValue:position forKey:orderKey] ;
    NSLog(@"passed!") ;

    Produces console output:

    Entry responds to setter and getter, looks good!!
    [<Entry 0x3d23c0> setValue:forUndefinedKey:]: this class is not key
    value coding-compliant for the key position.

    What could cause the 'not key value coding-compliant' error?

    - Entry is declared as a subclass of NSManagedObject
    - therefore Entry has no instance variables
    - In my .xcdatamodel, I have an Entry entity with
        - class set to 'Entry'
        - 'No Parent Entity'
        - Not 'Abstract'
        - No 'User Info'
        - No 'Configurations'
        - has one 'attribute':
              - name = 'position'
              - not 'Optional'
              - not 'Transient'
              - Type = 'Integer 32'
              - 'Min Value', 'Max Value' and 'Default Value' are blank
        - also has two relationships

    One other weird thing that I notice is that if I change the last line
    in the code above to:

    [glueObject setPosition:position] ;

    I get exactly the same 'not KVC compliant' error.  I think that's
    weird because setPosition: is not asking any KVC magic; it's just
    sending a plain-old message to a method which has just passed the -
    respondsToSelector: test.

    Here are the accessors in @implementation Entry (generated by
    mogenerator, were in superclass @implementation _Entry, doesn't
    matter if in Entry or _Entry)

    - (NSNumber*)position {
        [self willAccessValueForKey:@"position"];
        NSNumber *result = [self primitiveValueForKey:@"position"];
        [self didAccessValueForKey:@"position"];
        return result;
    }

    - (void)setPosition:(NSNumber*)value_ {
        [self willChangeValueForKey:@"position"];
        [self setPrimitiveValue:value_ forKey:@"position"];
        [self didChangeValueForKey:@"position"];
    }

    Thanks again folks,

    Jerry
  • You said ...

    > // glueClass is a variable of type Class, value is class 'Entry'

      ... but the runtime said ...

    > [<Entry 0x3d23c0> setValue:forUndefinedKey:]: this class is not key
    > value coding-compliant for the key position.

      ... which means you lied. ;-) The object in question (in the log)
    says it's of type "Entry". Perhaps your glueClass pointer is not
    pointing to where you really meant to point it?

    --
    I.S.
  • On 9/19/07, I. Savant <idiotsavant2005...> wrote:
    > You said ...
    >
    >> // glueClass is a variable of type Class, value is class 'Entry'

      Wait a minute ... let me retract that last attempt at comedic
    effect. I somehow missed the "value is class 'Entry'" part. My
    apologies.

      On initial inspection, this all looks "on the up 'n' up" but does it
    work if you remove the NSMutableSet category?

    --
    I.S.
  • Okay, I swear this is the last message I'm going to fire off on this
    subject while I'm trying to rush out the door to face rush hour
    traffic ...

    id glueObject = [[glueClass alloc] init] ;

      ... if this is meant to be used with Core Data, it must be a
    subclass of NSManagedObject and cannot be created this way. You have
    to do it Core Data's way:

    id glueObject = [NSEntityDescription
    insertNewObjectForEntityForName:@"Entry" inManagedObjectContext:[self
    managedObjectContext]];

      I have no idea if this is the cause of your KVC compliance problem,
    but this is definitely *a* problem. Sorry for the earlier noise; I'm
    rushed and should just have kept my mouth shut. :-D

    --
    I.S.
  • On 2007 Sep, 19, at 13:58, I. Savant wrote:

    > ... if this is meant to be used with Core Data, it must be a
    > subclass of NSManagedObject and cannot be created this way. You have
    > to do it Core Data's way...
    >
    > I have no idea if this is the cause of your KVC compliance problem,
    > but this is definitely *a* problem.

    THANKS!  Indeed, that problem was also causing the KVC problem.  I
    had been worried about how that Entry was going to get into the
    store, but hadn't thought about it too much yet.  Sometimes those
    error messages are so definitive, I forget to take my blinders off.

    Hey, I take back all the bad things you said about yourself, rushing
    out the door.  It was very helpful to me and I hope you got home safe.
  • On Sep 19, 2007, at 5:27 PM, Jerry Krinock wrote:

    > THANKS!  Indeed, that problem was also causing the KVC problem.  I
    > had been worried about how that Entry was going to get into the
    > store, but hadn't thought about it too much yet.  Sometimes those
    > error messages are so definitive, I forget to take my blinders off.
    >
      Well, at least I was able to save *some* face there. Still,
    would've been funnier had the first message been accurate ... to me,
    anyway. ;-)

    --
    I.S.
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today