Building delegates like they do in UIKit
In UIKit, I often see delegate properties being declared as id
and those delegates being able to access the performSelector
method. In contrast, when I write custom protocols to be used as delegates, those delegates need to be of type NSObject
to access performSelector
.
Take this example protocol:
@protocol CustomDelegate
- (void)doAwesomeness;
@end
In order to access performSelector
, I would need to declare the delegate as:
NSObject<CustomDelegate> *delegate;
rather than the more common:
id<CustomDelegate> delegate;
Is there some magic that Apple are sprinkling on their protocols that allows them access to greater functionality that I'm not?
Well, yes and that magic isn't even hidden just easy to miss - it's the NSObject
protocol.
Confusingly,
NSObject
is both a protocol and a concrete type - the concrete typeNSObject
conforms to the protocolNSObject
. Here we are talking about the protocol not the conrete type
Let's take UITextDelegate
as our UIKit example and look it more closely. The first thing you will notice is that, unlike CustomDelegate
, UITextDelegate
inherits from the protocol NSObject
:
@protocol UITextFieldDelegate <NSObject>
Any type that wants to conform UITextFieldDelegate
must also conform to NSObject
. NSObject
is where performSelector
is declared. So it is safe to call performSelector
on that property as the compiler knows that UITextFieldDelegate
is a specialised form of NSObject
.
CustomDelegate
doesn't enforce that a type that conforms to it must also conform to NSObject
. The compiler cannot guarantee that any conforming type will implement performSelector
, so it prevents potentially unsafe calls to performSelector
on that property.
Updating CustomDelegate
to inherit the NSObject
protocol means that I can use id
as the property type, allowing my protocols to feel more like those we get from UIKit.