Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two class methods, same name, different signatures: How to force compiler to use intended one?

How do I force the compiler to select the desired method from a set of class methods sharing the same name?

/* Use +[MyClass port](UInt16 (*)(id, SEL),
 * not +[NSPort port](NSPort *(*)(id, SEL)). */
UInt16 port = [[self class] port];

I have an Objective-C class with a class method:

+ (UInt16)port;

NSPort has a convenience constructor whose signature conflicts with this:

+ (NSPort *)port;

Sending +port to my class results in a compiler warning:

UInt16 port = [[self class] port];
    W: Multiple methods named '+port' found
    W: Using '+(NSPort *)port'
    W: Also found '+(UInt16)port'

Fail: The compiler has chosen the wrong method signature.

Type inference fail: Using [[(MyClass *)self class] port] does not cadge it into using the right method.

ETA: Here is the workaround I am using for now:

#import <objc/runtime.h>

Class c = [self class];
SEL s = @selector(port);
typedef UInt16 (*PortIMP)(id, SEL);
PortIMP MyClassGetPort = (PortIMP)class_getMethodImplementation(c, s);
UInt16 port = MyClassGetPort(c, s);

It is good in that:

  • It handles dispatching to any subclass implementation correctly.
  • It is confined to the implementation file, so this ugliness is not inflicted on anyone but the implementer.

It is bad in that it won't help anyone else who wants to call the method.

like image 481
Jeremy W. Sherman Avatar asked Apr 11 '11 16:04

Jeremy W. Sherman


1 Answers

Interesting… there doesn’t seem to be an obvious solution to this one.

You could use a protocol to declare the methods you need, for instance

@protocol MyClassProtocol
@optional 
- (UInt16)port;
@end

then do

UInt16 port = [(id <MyClassProtocol>)[self class] port];

Not pretty, but it does work.

like image 175
al45tair Avatar answered Sep 24 '22 13:09

al45tair