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?
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.