Search code examples
objective-ckvc

KVC on id type conforming to a protocol


I have stumbled upon a problem with key value coding in Xcode 6. It seems as it's impossible to use key value coding on id's conforming to a protocol.

When a property is declared as id the compiler agrees

@property (nonatomic, strong) id foo;

[foo setValue:@"value" forKey:@"key"];

When I set the id to conform to a protocol I get a compiler error. "No known instance method for selector ...".

@property (nonatomic, strong) id<MyProtocol> foo;

[foo setValue:@"value" forKey:@"key"];

It works if I set the type to NSObject, like this:

@property (nonatomic, strong) NSObject<MyProtocol> *foo;

[foo setValue:@"value" forKey:@"key"];

The protocol "MyProtocol" conforms to NSObject, but as far as I understand the object is required to be a subclass of NSObject in order for KVC to work. But why does the first scenario work but not the second?


Solution

  • This isn't new in Xcode 6. (I just tested Xcode 5.1.1 and got an error.) The rules are:

    • The compiler will let you send any message to a bare id.

    • The compiler will only let you send a message to id<Protocol1, Protocol2, Protocol3, ...> if the message is defined by one of the named protocols.

    • The compiler will only let you send a message to SomeClass<Protocol1, Protocol2, Protocol3, ...> if the message is defined by one of the named protocols, or by the class. Messages defined by the class include messages defined by its superclasses and its categories.

    The setValue:forKey: method is defined in the NSKeyValueCoding category on the NSObject class. It's not defined on the NSObject protocol.