不匹配的-init方法名称

时间:2010-10-31 13:29:59

标签: objective-c xcode

我发现了一个奇怪的情况,在XCode中产生一个我认为不是有效警告的编译器警告。

作为一个例子,我创建了两个类,ClassA& ClassB,它们都有一个名为-initWithSomething的init方法: 一个(NSDate *)作为“东西”而另一个需要(NSString *)

A类

// ClassA.h
#import <Foundation/Foundation.h>

@interface ClassA : NSObject {
}
-(id)initWithSomething:(NSDate *)something;
@end

// ClassA.m
#import "ClassA.h"

@implementation ClassA
-(id)initWithSomething:(NSDate *)something {
    if (self = [super init]) {
    }
    return self;
}
@end

B类

// ClassB.h
#import <Foundation/Foundation.h>

@interface ClassB : NSObject {
}
-(id)initWithSomething:(NSString *)something;
@end

// ClassB.m
#import "ClassB.h"

@implementation ClassB
-(id)initWithSomething:(NSString *)something {
    if (self = [super init]) {
    }
    return self;
}
@end

同时使用ClassA和amp;的另一个类的实现ClassB的

#import "ExampleClass.h"
#import "ClassA.h"
#import "ClassB.h"

@implementation ExampleClass

-(void)doSomething {
    NSDate *date = [NSDate date];
    NSString *string = [NSString stringWithFormat:@"Test"];

    ClassA *classA = [[ClassA alloc] initWithSomething:date];
    ClassB *classB = [[ClassB alloc] initWithSomething:string]; // Produces "Incompatible pointer types sending 'NSString *' to parameter of type 'NSDate *'
    ClassB *classB2 = [[ClassB alloc] initWithSomething:[NSString stringWithFormat:@"Test"]]; // Does NOT produce a warning
    ClassB *classB3 = [[ClassB alloc] initWithSomething:@"Test"]; // Produces the same warning as above.

    [classA release];
    [classB release];
    [classB2 release];
    [classB3 release];
}

这是编译器错误吗?似乎这些行中的任何一行都不会产生警告,特别是因为“classB2”被启动的行不会产生警告。
这段代码实际上运行正常,正确的类'-initWithSomething:被调用并传递适当类型的参数。

显然,更明确的方法名称可以避免这个问题,但我想知道为什么编译器无法处理这个问题。

注意: 我应该补充一点,这似乎只发生在-init方法中,任何其他实例或类函数似乎都不会产生警告。

3 个答案:

答案 0 :(得分:3)

我认为问题在于+alloc会返回通用id

这意味着可以在其上调用任何方法,并且编译器将看到导入具有签名-initWithSomething的第一个方法用于类A,其期望类型为{{{ 1}}。

此外,我确信方法NSDate *会返回+stringWithFormat,该id可与NSDate兼容。

修改

解决此问题的简单方法:

@interface ClassA

+(ClassA *) typeSafeAlloc;

// ...
@end

@implementation ClassA

+(ClassA *) typeSafeAlloc
{
    // self is the class variable,  which is the same as:
    // return [ClassA alloc];
    return [self alloc];
}
@end

使用ClassB重复该过程(typeSafeAlloc返回ClassB个对象)

答案 1 :(得分:2)

alloc返回一个id类型的对象,因此编译器假定initWithSomething属于Class A(它遇到的具有方法名的第一个类接口)。

有点像 [(ClassB*)[ClassB alloc] initWithSomething:string];应解决问题。

答案 2 :(得分:1)

查看+stringWithFormat

的返回类型
  

返回使用给定格式字符串作为模板创建的字符串,其余的参数值将替换为该模板。

     

+ (id)stringWithFormat:(NSString *)format, ...

(来自http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html

编译器知道字符串是NSString*,与@"literals"相同。然而,id可以是任何内容(甚至是NSSDate*)。