I'd like to specify an Objective-C protocol with an optional routine. When the routine is not implemented by a class conforming to the protocol I'd like to use a default implementation in its place. Is there a place in the protocol itself where I can define this default implementation? If not, what is the best practice to reduce copying and pasting this default implementation all over the place?
You can have properties in a protocol, provided every class that conforms to your protocol have a corresponding @synthesize for that property, or provide a getter and setter. But with a class category you generally can't add instance variables to a class.
In Objective-C, protocols are declared with the “@protocol” keyword. Below is an example of declaring a protocol containing one required method. In Swift, the syntax is a little different but the idea is the same. In Objective-C, you add the protocol name in angle brackets beside the class interface declaration.
A class interface declares the methods and properties associated with that class. A protocol, by contrast, is used to declare methods and properties that are independent of any specific class. Protocols can include declarations for both instance methods and class methods, as well as properties.
Objective-C protocols have no affordance for default implementations. They are purely collections of method declarations that can be implemented by other classes. The standard practice in Objective-C is to test an object at runtime to see if it responds to the given selector before calling that method on it, using -[NSObject respondsToSelector:]. If e object does not respond to the given selector, the method isn't called.
One way you could achieve the result you're looking for would be to define a method encapsulating the default behavior you're looking for in the calling class, and call that method if the object doesn't pass the test.
Another approach would be to make the method be required in the protocol, and provide default implementations in the superclasses of any classes wherein you may not want to provide a specific implementation.
There are probably other options as well, but generally speaking there isn't a particular standard practice in Objective-C, except perhaps to just not call the given method if it hasn't been implement by the object, per my first paragraph, above.
There is no standard way for doing that as protocols should not define any implementations.
Since Objective-C comes with a neat runtime, you can of course add such a behavior if you really think you need to do it that way (and there's no possibility by achieving the same with inheritance).
Say you declared MyProtocol, then just add an interface with the same name in the .h file under your protocol declaration:
@interface MyProtocol : NSObject <MyProtocol> + (void)addDefaultImplementationForClass:(Class)conformingClass; @end
And create a corresponding implementation file (using MAObjCRuntime for readability here, but the standard runtime functions wouldn't be much more code):
@implementation MyProtocol + (void)addDefaultImplementationForClass:(Class)conformingClass { RTProtocol *protocol = [RTProtocol protocolWithName:@"MyProtocol"]; // get all optional instance methods NSArray *optionalMethods = [protocol methodsRequired:NO instance:YES]; for (RTMethod *method in optionalMethods) { if (![conformingClass rt_methodForSelector:[method selector]]) { RTMethod *myMethod = [self rt_methodForSelector:[method selector]]; // add the default implementation from this class [conformingClass rt_addMethod:myMethod]; } } } - (void)someOptionalProtocolMethod { // default implementation // will be added to any class that calls addDefault...: on itself }
Then you just have to call
[MyProtocol addDefaultImplementationForClass:[self class]];
in the initializer of your class conforming to the protocol and all default methods will be added.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With