2

Possible Duplicate:
Why is my object not key value coding-compliant?

I'm having a dictionary and I want to add keys/values to a custom class, but i always get the error, that the class is not KVC compliant, but the Apple documents state that it should be.

My code:

ContactObject.h:

@interface ContactObject : NSObject
     + (ContactObject *)testAdding;
@end

ContactObject.m:

@implementation ContactObject

- (id)init {
    self = [super init];
    if (self) {
        // customize

    }

    return self;

}

+ (ContactObject *)testAdding
{
    // create object
    ContactObject *theReturnObject = [[ContactObject alloc] init];

    [theReturnObject setValue:@"Berlin" forKey:@"city"];
    [theReturnObject setValue:@"Germany" forKey:@"state"];

    return theReturnObject;

}

@end

I think I'm missing something very stupid :)

Please, any help appreciated ...

Greetings, matthias

Community
  • 1
  • 1
matttrakker
  • 204
  • 3
  • 15

4 Answers4

5

Actually to be KVC compliant:

How you make a property KVC compliant depends on whether that property is an attribute, a to-one relationship, or a to-many relationship. For attributes and to-one relationships, a class must implement at least one of the following in the given order of preference (key refers to the property key):

  1. The class has a declared property with the name key.
  2. It implements accessor methods named key and, if the property is mutable, setKey:. (If the property is a Boolean attribute, the getter accessor method has the form isKey.)
  3. It declares an instance variable of the form key or _key.

I don't see any of these three implemented. You need to have at least properties that you are trying to set through KVC, the default NSObject implementation is able to set properties through setValue:forKey: but you must declare them.

Jack
  • 131,802
  • 30
  • 241
  • 343
2

You need to declare every property that will be used:

@interface ContactObject : NSObject

@property (nonatomic,copy, readwrite) NSString* city;
@property (nonatomic, copy, readwrite) NSString* state;

+ (ContactObject *)testAdding;

@end

Or use a NSMutableDictionary object.

For example:

NSMutableDictionary* dict= [NSMutableDictionary new];
[dict setObject: @"Berlin" forKey: @"city"];
[dict setObject: @"Germany" forKey: @"state"];
Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
1

You need to actually declare/implement properties. Key-Value Coding doesn't mean that every NSObject is automatically a key/value dictionary.

In this case you would need to declare:

@property (nonatomic, readwrite, copy) NSString* city;
@property (nonatomic, readwrite, copy) NSString* state;

in your @interface declaration.

ipmcc
  • 29,581
  • 5
  • 84
  • 147
  • "nice try, but those fields are not safe, could be city, could be state, could be nearly everything, that's why I wanted to do this dynamically..." – matttrakker Jan 05 '13 at 21:29
  • 1
    If you need to be able to use any string key, then you will need to either use an NSMutableDictionary, or you'll need to make an iVar that's an NSMutableDictionary and then write implementations of `valueForUndefinedKey:` and `setValue:forUndefinedKey:` that forward unknown set and get operations for unknown keys to the NSMutableDictionary. – ipmcc Jan 05 '13 at 21:31
1

ObjC is dynamic in some ways, but it's not really dynamic as far as storage in classes. If you want ContactObject to be KVC-compliant for certain keys, those keys need to exist in the class. The KVC Guide has this to say:

For properties that are an attribute or a to-one relationship, this requires that your class:

  • Implement a method named -<key>, -is<Key>, or have an instance variable <key> or _<key>. Although key names frequently begin with a lowercase letter, KVC also supports key names that begin with an uppercase letter, such as URL.

  • If the property is mutable, then it should also implement -set<Key>:. Your implementation of the -set<Key>: method should not perform validation.

The easiest way to accomplish that is to declare the keys you want as properties:

@property (copy, nonatomic) NSString * city;
@property (copy, nonatomic) NSString * state;

You can also declare an ivar and implement accessors yourself, but there's usually no good reason to do it that way -- declared properties will take good care of you.

jscs
  • 63,694
  • 13
  • 151
  • 195