Question

I've come across a strange scenario related to class inheritance in Objective-C.

Let's say i have three classes A, B and C that inherit from a base class X. Classes A, B and X have the constructor:

- (id)InitWithString:(NSString*)someString andDelegate:(id<SomeProtocol>)aDelegate

the only difference being that every class uses a different protocol for the delegate.

What happens is that for A and B the compiler tries to use the method from C. A warning informs me that the protocols required by class C's constructor is not implemented by the provided delegate. There is nothing wrong with the delegate itself, since each class has a delegate that implements the right protocol for the classes' own constructor. Everything works fine at run time and the right functions are called for all classes.

I tried having the constructors return A*, B* or C* instead of the anonymous id, though this still doesn't solve the problem.

The only thing that works is making a cast to the right class like this:

instanceOfA = [(A*)[A alloc] InitWithString:@"" andDelegate:aDelegate];

This seems superfluous and unnecessary. I'm probably missing something obvious here.

Was it helpful?

Solution

I'm not sure how clever the analyzer actually is for these cases and suspect you simply hit one of its limitations.

What you're observing is the compiler seeing the object as id and picking the first method that matches the signature. Try moving the order you including your classes around and you should see that it always picks the selector that gets defined first.

A way to get around this is to initialize the class in two steps:

ClassA *test = [ClassA alloc];
test = [test initWithString:@"" andDelegate:delegate];

In this case, the analyzer knows test is of type ClassA and picks the right selector. It seems that it's not so clever as to tell of what type intermediary objects are that are not assigned to a variable and then just always assumes them to be id.

OTHER TIPS

The problem is with the declaration of the method which defines a parameter of a specified type.

You should make the declaration as generic as possible to be valid for all the classes of the object passed as last parameters. if all the protocol inherit from a parent protocol, then you can declare the method as - (id)initWithString:(NSString*)someString andDelegate:(id<ParentProtocol>)aDelegate; differently, you can use the more generic definition - (id)initWithString:(NSString*)someString andDelegate:(id)aDelegate

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top