Incorrect method names

I found a strange script that causes a compiler warning in Xcode, which I believe is not a valid warning.

As an example, I created two classes: ClassA and ClassB, which have an init method called -initWithSomething: One accepts (NSDate *) as "something" and the other accepts (NSString *)

Class A

// ClassA.h #import <Foundation/Foundation.h> @interface ClassA : NSObject { } -(id)initWithSomething:(NSDate *)something; @end // ClassA.m #import "ClassA.h" @implementation ClassA -(id)initWithSomething:(NSDate *)something { if (self = [super init]) { } return self; } @end 

Class B

 // ClassB.h #import <Foundation/Foundation.h> @interface ClassB : NSObject { } -(id)initWithSomething:(NSString *)something; @end // ClassB.m #import "ClassB.h" @implementation ClassB -(id)initWithSomething:(NSString *)something { if (self = [super init]) { } return self; } @end 

An implementation of another class that uses both ClassA and ClassB

 #import "ExampleClass.h" #import "ClassA.h" #import "ClassB.h" @implementation ExampleClass -(void)doSomething { NSDate *date = [NSDate date]; NSString *string = [NSString stringWithFormat:@"Test"]; ClassA *classA = [[ClassA alloc] initWithSomething:date]; ClassB *classB = [[ClassB alloc] initWithSomething:string]; // Produces "Incompatible pointer types sending 'NSString *' to parameter of type 'NSDate *' ClassB *classB2 = [[ClassB alloc] initWithSomething:[NSString stringWithFormat:@"Test"]]; // Does NOT produce a warning ClassB *classB3 = [[ClassB alloc] initWithSomething:@"Test"]; // Produces the same warning as above. [classA release]; [classB release]; [classB2 release]; [classB3 release]; } 

Is this a compiler error? It seems that none of these lines should cause warnings, especially since the line in which "classB2" is included does not cause any warnings.
This code really works fine, the correct class is' -initWithSomething: is called and passed the corresponding type of argument.

Obviously, more explicit method names will avoid this problem, but I would like to know why the compiler cannot handle this.

Note : I have to add that this is only like the -init methods, any other functions of the instance or class do not seem to generate warnings.

+4
source share
3 answers

I think the problem is that +alloc returns a common id .

This means that any method can be called on it, and the compiler will see that the first imported method, signed with -initWithSomething , is for class A , which expects an object of type NSDate * .

In addition, I believe that the +stringWithFormat method returns an id that can be compatible with NSDate .

EDIT:

A simple solution to this problem:

 @interface ClassA +(ClassA *) typeSafeAlloc; // ... @end @implementation ClassA +(ClassA *) typeSafeAlloc { // self is the class variable, which is the same as: // return [ClassA alloc]; return [self alloc]; } @end 

And repeat the process with ClassB (with type SafeAlloc returning a ClassB object)

+3
source

alloc returns an object of type id, and therefore the compiler assumes that initWithSomething belongs to Class A (the first class interface it encounters has a method name).

Somthing like [(ClassB*)[ClassB alloc] initWithSomething:string]; should solve the problem.

+2
source

Look at the return type +stringWithFormat

Returns a string created using the specified format string as a template into which the rest of the argument values ​​will be replaced.

+ (id)stringWithFormat:(NSString *)format, ...

(from http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html )

The compiler knows that the string is NSString* , the same with @"literals" . However, id can be anything (even NSSDate* ).

+1
source

All Articles