What's wrong with using a category on NSObject to provide a default protocol implementation?
Asked Answered
L

1

11

I've been looking for a way to use optional protocol methods and have clean code. In other words:
1: No respondsToSelector: calls all over my code
2. Should work for any method signature, so a category method on NSObject making the check and calling performSelector: is out (and NSInvocation has problems cooperating with ARC)
3: This solution, IMO, pretends to be universal but has all the drawbacks of 1

I eventually came up with this idea:

@protocol MyProtocol <NSObject>
@optional
-(void)optionalMethod;
@end

@interface ClassA : NSObject <MyProtocol>
@end

@implementation ClassA

-(void)optionalMethod{
     NSLog(@"ClassA implements optionalMethod");
}

@end

@interface ClassB : NSObject <MyProtocol>
@end

@implementation ClassB
//classB does not implement optionalMethod
@end

@interface NSObject (DefaultMyProtocolImplementation)
-(void)optionalMethod;
@end

@implementation NSObject (DefaultMyProtocolImplementation)
-(void)optionalMethod{
     NSLog(@"%@ does not implement optionalMethod", NSStringFromClass([self class]));
}
@end

It seems to work, i.e.:

...
ClassA *objA = [[ClassA alloc] init];
ClassB *objB = [[ClassB alloc] init];

[objA optionalMethod]; //prints "ClassA implements optionalMethod"
[objB optionalMethod]; //prints "ClassB does not implement optionalMethod"

While many places online discuss this problem, I haven't stumbled upon this solution, which makes me think there's something wrong with it -- some major case where it will fail, or be unpredictable.

Should I just do it, or are my concerns valid?

Lowlife answered 12/10, 2013 at 0:55 Comment(2)
Related: Creating a category for classes that implement a specific protocol, and Alex Gray's answer to Defining categories for protocols in Objective-C, which points to libextobjc.Brentbrenton
Only thing I can really think of so far is that you won't get a compiler warning for [objectWhichDoesNotDeclareConformanceToTheProtocol theOptionalProtocolMethod]; This is actually how optional protocol methods were originally implemented: Informal protocol in ObjC The other thing is, methods that you add to framework classes should ideally be prefixed to avoid collisions.Brentbrenton
D
8

Methods added to existing system classes should be prefixed somehow. I.e. exec_myMethod or exec_doSomethingToThis:. So, your solution is in violation of that.

Beyond that, it also means that a class cannot opt out of whatever the default @optional method's behavior might be (which is basically nothing because your default implementation really should be a no-op).

So, no, overall, there isn't something horrendously wrong with providing a default implementation beyond the violation of the should add prefix rule for adding methods via category to existing classes. But that isn't a hard rule.

The other downside is that you are polluting the method namespace. This will be a disadvantage during development in that Xcode will code complete all the methods, easily avoided by simply not exposing the declarations (which don't need to be exposed). At runtime, it means that respondsToSelector: isn't useful for these methods, but that is kind of by design.

Still... it smells to this old timer's code olfactory center.

Dyne answered 15/10, 2013 at 3:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.