2014-01-12 54 views
2

我有一个简单的类层次结构,其构造函数使用instancetype而不是id作为返回类型。如果我想转发给超类的构造函数,我得到这样的警告:使用实例类型与ID的类层次结构

返回车辆*从方法*返回车:接口车辆没有车

如果我切换的继任者从instancetypeid,当然,由于类型严格性较低,错误消失。推荐的方法是什么?

Vehicle.h

@interface Vehicle 

- (instancetype)initWithIdentifier:(NSString *)anIdentifier 

@end 

Vehicle.m

@implementation Vehicle 

- (instancetype)initWithIdentifier:(NSString *)anIdentifier { 
    self = [super init]; 

    if (self) { 
     // do a bunch of stuff to construct the object 
    } 

    return self;  
} 

@end 

Car.h

@interface Car : Vehicle 

- (instancetype)initWithCarID:(NSString *)aCarId 

@end 

Car.m

@implementation Car 

- (instancetype)initWithCarID:(NSString *)aCarId { 
    // I want to forward the call to the parent and preserve the 
    // two different constructor signatures 

    // The following line produces this warning: 
    // Returning Vehicle * from a method returning Car *: interface Vehicle is not a successor of Car 
    return [super initWithVehicleIdentifier:aCarId]; 
} 

@end 

回答

1

对于-init*方法,这是instancetype是不必要的。编译器会自动将id视为instancetype

自己尝试一下,看看有什么警告,从下面的代码生成:

[[[NSArray alloc] init] length]; 
[[[NSArray alloc] initWithContentsOfURL:nil] length]; 

见NSHipster年代instancetype书面记录更多的细节。


更新

作为一项规则,instancetype为返回自己的一个实例的任何方法是有用的。由于命名约定规则,-init*只是此规则的一个例外。

Objective-C就像英文语法:每条规则都有例外。

+0

因此instancetype只对类构造函数是必需的吗? –

+0

隐含相关结果类型的方法是'alloc','+ new','-init','-retain','-autorelease'和'-self',@Will。更多细节[在Clang文档中](http://clang.llvm.org/docs/LanguageExtensions.html#related-result-types)。 –

+0

@我会更新我的答案。 –

1

我会用“ID”,因为其通常的方式来实现这样的事情 - 看到苹果的示例代码等,如果你真的想用instancetype然后与狮子座的答案去。

你得到警告的原因是因为“Vehicle”(你正在返回的)的一个实例并不完全是“Car”的一个实例。它会工作,但你已经告诉编译器该方法将返回一个“Car”的实例。 有关更多信息,请参阅此question

1

尝试以下操作:

@implementation Car 
- (instancetype)initWithCarID:(NSString *)aCarId { 

    self = [super initWithVehicleIdentifier:aCarId]; 
    return self; 
} 

或者,干脆将返回的对象:

- (instancetype)initWithCarID:(NSString *)aCarId { 
    return (Car*)[super initWithVehicleIdentifier:aCarId]; 
}