2011-06-22 56 views
4

我有一個奇怪的情況,我有兩個協議和幾個類的初始化與委託實現協議。標準的東西,真的。但是,XCode 4正在拋出一些錯誤的警告,我似乎無法將自己的腦袋包裹起來。以下是顯示定義和實現的摺疊源列表。奇怪的或錯誤的警告與多個@協議

// CLASS A 
@protocol ClassADelegate <NSObject> 
-(void) DoSomething; 
@end 

@interface ClassA : NSObject { } 
+(ClassA *) classWithDelegate:(id<ClassADelegate>)d; 
-(ClassA *) initWithDelegate:(id<ClassADelegate>)d; 
@end 

@implementation ClassA 
+(ClassA *) classWithDelegate:(id<ClassADelegate>)d { 
    return [[[ClassA alloc]initWithDelegate:d]autorelease]; 
} 
-(ClassA *) initWithDelegate:(id<ClassADelegate>)d{ 
    self = [super init]; 
    return self; 
} 
@end 

// CLASS B 
@protocol ClassBDelegate <NSObject> 
-(void) DoSomethingElse; 
@end 

@interface ClassB : NSObject<ClassADelegate> { } 
+(ClassB *) classWithDelegate:(id<ClassBDelegate>)d; 
-(ClassB *) initWithDelegate:(id<ClassBDelegate>)d; 
-(void) DoSomething; 
@end 

@implementation ClassB  
+(ClassB *) classWithDelegate:(id<ClassBDelegate>)d { 
    return [[[ClassB alloc]initWithDelegate:d]autorelease]; 
} 
-(ClassB *) initWithDelegate:(id<ClassBDelegate>)d{ 
    self = [super init]; 
    return self; 
} 
-(void) DoSomething { 

} 
@end 

現在,這裏的瘋狂的一部分 - 在ClassB的的在這條線的靜態構造函數:

return [[[ClassB alloc]initWithDelegate:d]autorelease]; 

...編譯器拋出一個警告,沒有任何意義:

"Type 'id <ClassBDelegate>' does not conform to the 'ClassADelegate' protocol" 

我錯過了什麼嗎?選擇器清楚地將類型設置爲id<ClassBDelegate>,所以d應該是正確的。這只是編譯器感到困惑嗎?

回答

4

編譯器越來越困惑,因爲你有具有相同名稱但返回/參數類型不同的方法,Objective-C與方法重載並不完全是朋友。

當編譯器分析:

[[[ClassB alloc]initWithDelegate:d]autorelease]; 

它開頭:

[ClassB alloc] 

+[ClassB alloc]返回類型是id,所以上面的表達式是id類型。下一步是分析:

[##expression of type id## initWithDelegate:d] 

,並在這一點上有兩種可能的方法:

-(ClassA *) initWithDelegate:(id<ClassADelegate>)d; 
-(ClassB *) initWithDelegate:(id<ClassBDelegate>)d; 

兩者都是可能的,因爲接收器是id型的,所以它可以是一個ClassA實例或者一個ClassB實例。但是,aha!,第一個參數的協議不同,所以不應該有任何混淆。但是,方法查找基於兩個變量:無論是類還是實例方法,以及相應的選擇器。在上面的方法中,兩者都是實例方法,並且都具有相同的選擇器。編譯器決定選擇第一個。

一個解決方法是告訴編譯器,通過[ClassB alloc]返回的對象是ClassB *型的,而不是通用型id的:

return [[(ClassB *)[ClassB alloc]initWithDelegate:d]autorelease]; 

,也許在所有相似的類使用這種模式。

另一個解決方法是爲這些方法提供不同的名稱,例如-initWithClassADelegate:-initWithClassBDelegate:

+2

是的。請參閱['-Wstrict-selector-match'選項](http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Objective_002dC-and-Objective_002dC_002b_002b-Dialect-Options.html#index-Wstrict_002dselector_002dmatch -207) –

+0

確認;從參數類型移除''到' - [ClassA initWithDelegate:]'會導致警告消失。很好解釋! –

+0

謝謝!我猜我的困惑在於我的假設,[ClassB alloc]返回了ClassB類型的實例而不是id。 – jtalarico