【发布时间】:2011-04-23 17:27:22
【问题描述】:
我以为我了解基本的 Objective-C 就 alloc 和 init... 方法而言,但显然我不了解。我将遇到的问题归结为下面的最小示例。 (例如,我将所有源文件放入一个文件中,但如果将源文件拆分为多个源文件和头文件,问题也会像往常一样)。
以下是代码的作用以及运行时发生的情况的概要。
我定义了两个类 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 的答案也是一个不错的答案,因为它教授了一种签名命名实践,有助于避免该问题。谢谢两位!
标签: objective-c xcode4