命名超类“消息”时的Objective-C-Runtime Bug

时间:2010-05-17 14:22:53

标签: objective-c runtime

我有以下课程hierachy:

@interface Message : NSObject {}
@end

@implementation Message
- (void) dealloc
{
    // I won't be called
    [super dealloc];
}
@end

@interface FooMessage : Message {}
@end

@implementation FooMessage
- (void) dealloc
{
    // should call Message - dealloc
    [super dealloc];
}
@end

以下单元测试:

- (void) test
{
    FooMessage* msg = [[FooMessage alloc] init];
    [msg release];
}

EXC_BAD_INSTRUCTION测试将始终失败。 FooMessagedealloc中调用它的超类析构函数,但调用永远不会到达那里。而是,Objective-C运行时将调用解析到另一个位置: StackTrace and disassembly

如果将Message基类重命名为其他内容,则不会发生错误,例如AbstractMessage。看来还有另一个名为Message的类,其定义不公开。

这是一个错误吗?这里到底发生了什么?我是否违反了任何命名限制(即使我认为编译器应该警告我)?

这是XCode 3.1。为iPhone OS 3.0编译。

1 个答案:

答案 0 :(得分:8)

Objectve-C缺乏名称空间的概念。这个问题是众所周知的,并且通常使用前缀命名空间(例如 NS Object或 MK MapView)来解决。您可以将消息类命名为JrMessage,以避免与名为Message的(未记录的)类发生冲突。

编译器只能在知道其他类时发出警告。对于私有的,未记录的类,通常情况并非如此。处理此问题的最佳方法是通过在每个类上使用前缀来避免冲突。这也有助于防止未来的冲突,当Apple为新版本的操作系统添加类时(编译器显然无法警告)。

修改

进一步调查表明,竞争类来自名为“MIME.framework”的私有框架,至少在iPhone模拟器上:

NSLog(@"Message class: %@", [[NSBundle bundleForClass:NSClassFromString(@"Message")] bundlePath]);

... Message class: /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.1.3.sdk/System/Library/PrivateFrameworks/MIME.framework

您可能希望在bug report

中添加此信息