2010-10-31 76 views
4

我發現了一個奇怪的場景,它在XCode中產生了一個編譯器警告,我不相信這是一個有效的警告。不匹配-init方法名

作爲一個例子我創建兩個類,ClassA的& ClassB的,在都具有稱爲-initWithSomething一個init方法: 一個接受一個(的NSDate *)作爲 「東西」,而另一個爲(的NSString *)

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 

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 

同時使用ClassA的& 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]; 
} 

另一個類的實現這是一個編譯器錯誤?似乎這些行中的任何一行都不應該產生警告,尤其是因爲「classB2」所在的行不會產生警告。
此代碼實際上工作正常,調用了正確的類'-initWithSomething:並傳遞了適當類型的參數。

顯然,更明確的方法名稱將避免這個問題,但我想知道爲什麼編譯器無法處理這個問題。

注意: 我要補充,這似乎只與-init的方法來進行,其他任何實例或類的功能似乎並沒有產生警告。

+0

我不知道爲什麼有人會低估這個,這是一個很好的問題 – 2010-10-31 13:41:55

回答

3

我認爲問題是+alloc返回一個通用的id

這意味着可以調用任何方法,並且編譯器將看到具有簽名-initWithSomething的導入的第一個方法用於類A,該類需要NSDate *類型的對象。

此外,我確實認爲方法+stringWithFormat返回id可以與NSDate兼容。

編輯:

一個簡單的解決了這個問題:

@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 

,重複與ClassB的過程(與typeSafeAlloc返回ClassB對象)在返回類型

+0

很酷,謝謝你的例子。 – George 2010-10-31 14:08:26

2

alloc返回一個類型爲id的對象,因此編譯器假定initWithSomething屬於Class A(它遇到的具有方法名稱的第一個類接口)。

類似 [(ClassB*)[ClassB alloc] initWithSomething:string];應該解決問題。