无法弄清楚'警告:不兼容的Objective-C类型'

时间:2010-01-04 04:18:47

标签: objective-c cocoa

我有一个NSObject的子类,它实现了-(id)initWithRootElement:(MyElement *)e方法。 NSXMLDocument有一个相同的方法,它采用NSXMLElement。当我编译时,我收到以下警告:

warning: incompatible Objective-C types 'struct MyElement *', expected 'struct NSXMLElement *' when passing argument 1 of 'initWithRootElement:' from distinct Objective-C type

在这种情况下,我正在使用Xcode 3.2.1在SnowLeopard上使用Clang + LLVM进行编译,但这也适用于Leopard和SnowLeopard上的GCC 4.2。

我不明白为什么当NSXMLDocument必须首先从NSXMLNode继承时它为我的直接NSObject子类发出警告?它不应该知道-(id)initWithRootElement:(NSXMLElement *)e仅适用于与我的班级无关的NSXMLDocument吗?我能理解我是否试图重载该方法,但我不是。请告诉我,我不会发疯...

#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSXMLElement.h>
// Importing this here causes the warning...
// #import <Foundation/NSXMLDocument.h>

typedef NSObject MyElement;

@interface TestClass : NSObject
{
}

- (id)initWithRootElement:(MyElement *)element;
@end

@implementation TestClass
- (id)initWithRootElement:(MyElement *)element { return nil; }
@end

// ...but here it doesn't
// #import <Foundation/NSXMLDocument.h>

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // No warning! Inheritance: NSXMLDocument -> NSXMLNode -> NSObject
    NSXMLElement *xmlElement = [[NSXMLElement alloc] initWithName:@"foo"];
    [[TestClass alloc] initWithRootElement:xmlElement];

    // warning: incompatible Objective-C types 'struct MyElement *', expected 'struct NSXMLElement *' when passing argument 1 of 'initWithRootElement:' from distinct Objective-C type
    MyElement *element = [[MyElement alloc] init];
    [[TestClass alloc] initWithRootElement:element];

    [pool drain];
    return 0;
}

1 个答案:

答案 0 :(得分:11)

Objective-C不支持协变声明。

NSXMLDocument中initWithRootElement:的声明如下:

- (id)initWithRootElement:(NSXMLElement *)element;

这与您的声明不同:

- (id)initWithRootElement:(MyElement *)element;

因为参数类型不同。这会导致此代码行混淆(其中element的类型为MyElement * ...

[[TestClass alloc] initWithRootElement:element];

...因为+alloc的返回类型是id,因此编译器不知道使用哪种方法;预期哪种类型的论点。

使用面向Apple框架的Objective-C开发代码时,经验法则是永远不会为任何给定的选择器声明不同的参数

我有点惊讶第一个案例也没有发出警告。它可能应该。如果您有一个相当小的测试用例,请通过http://bugreport.apple.com/提交错误并将错误#附加到此问题(或我的回答)。