我以爲我瞭解基本的Objective-C,就alloc和init ...方法而言,但顯然我不知道。我已經將我遇到的問題歸結爲下面的最小示例。 (例如,我將所有源代碼放入一個文件中,但如果將源代碼拆分爲多個源文件和頭文件,問題就會與此相同)。alloc返回的Objective-C類與初始化時錯誤的類混淆
下面是代碼的概要以及當我運行它時會發生什麼。
我定義了兩個類MyInteger和MyFloat,它們幾乎完全相同,只不過一個類型是int而另一個類型是float。兩者都具有稱爲initWithValue的初始化方法:但是具有不同類型的參數。有一個#define來控制MyInteger類是否被定義,原因是它會導致程序的不同行爲,即使這個類從不使用。
main()只使用MyFloat。前兩行執行此操作:分配MyFloat的一個實例,並使用值50.0對其進行初始化。然後打印該值。根據是否定義了MyInteger,我得到兩個不同的輸出。
沒有MyInteger定義,正如我所期望的:
[4138:903] float parameter value:50.000000
[4138:903] Value:50.000000
(next two output lines omitted)
隨着MyInteger定義,出乎我的意料:
[4192:903] float parameter value:0.000000
[4192:903] Value:0.000000
(next two output lines omitted)
這在我看來,編譯器將調用initWithValue:彷彿它屬於到MyInteger類。 main()的接下來兩行通過將[MyFloat alloc]強制類型化MyFloat *來測試。即使定義了MyInteger,它也會生成輸出:
[4296:903] float parameter value:0.000000
[4296:903] Value:0.000000
[4296:903] float parameter value:50.000000
[4296:903] Value with cast:50.000000
請解釋發生了什麼事情!我現在已經掙扎了24小時以上,甚至到了打開大門讓一些熱量消失的時候,我的電腦可能會冷卻:-)謝謝!
另一個奇怪的是,如果我將MyInteger的定義降低到MyFloat的定義之下,那麼一切都是「好的」 - 正如我所期望的那樣。歷史證明我經常犯錯,因爲我懷疑編譯器應該受到指責。無論如何,這裏是編譯器和項目信息:使用Xcode 4.0.2。試用了所有3種編譯器選項(GCC 4.2,LLVM GCC 4.2和LLVM Compiler 2.0)。此示例的Xcode項目使用基於Foundation的Mac OS X命令行工具的標準配置進行設置。
#define DO_DEFINE_MYINTEGER 1
//------------- define MyInteger --------------
#if DO_DEFINE_MYINTEGER
@interface MyInteger : NSObject {
int _value;
}
-(id)initWithValue:(int)value;
@end
@implementation MyInteger
-(id)initWithValue:(int)value {
self= [super init];
if (self) {
_value= value;
}
return self;
}
@end
#endif
//------------- define MyFloat --------------
@interface MyFloat : NSObject {
float _value;
}
-(id)initWithValue:(float)value;
-(float)theValue;
@end
@implementation MyFloat
-(id)initWithValue:(float)value {
self= [super init];
if (self) {
NSLog(@"float parameter value:%f",value);
_value= value;
}
return self;
}
-(float)theValue {
return _value;
}
@end
//--------------- main ------------------------
int main (int argc, const char * argv[])
{
MyFloat *mf1= [[MyFloat alloc] initWithValue:50.0f];
NSLog(@"Value:%f",[mf1 theValue]);
MyFloat *mf2= [((MyFloat*)[MyFloat alloc]) initWithValue:50.0f];
NSLog(@"Value with cast:%f",[mf2 theValue]);
return 0;
}
我已經將Sherm Pendley的答案標記爲正確的答案,因爲它解釋了爲什麼發生這種情況的機制。來自NSResponder的答案也是一個很好的答案,因爲它教授的簽名命名實踐將有助於避免該問題。謝謝你們! – rene 2011-04-25 11:52:52