使用instancetype vs id的类层次结构

时间:2014-01-12 02:38:33

标签: objective-c

我有一个简单的类层次结构,我的构造函数使用instancetype而不是id作为返回类型。如果我想转发到超类的构造函数,我会收到此警告:

  

从返回Car *的方法返回Vehicle *:interface Vehicle不是Car的继承者

如果我从instancetype切换到id,当然,由于类型严格性较低,错误就会消失。建议的方法是什么?

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

3 个答案:

答案 0 :(得分:2)

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

自己尝试一下,看看从以下代码中产生了什么警告:

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

有关详细信息,请参阅NSHipster的instancetype文章。


<强>更新

通常,instancetype对于返回自身实例的任何方法都很有用。由于命名约定规则,-init*只是此规则的一个例外。

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

答案 1 :(得分:1)

我会使用“id”,因为它是实现这些东西的常用方法 - 请参阅Apple示例代码等。如果您真的想使用instancetype,那么请使用Leo的答案。

您收到警告的原因是因为“车辆”(您要返回的内容)的实例并不完全是“Car”的实例。它会工作,但你告诉编译器该方法将返回一个“Car”的实例。 有关详细信息,请参阅此question

答案 2 :(得分:1)

尝试以下方法:

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

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

或者,只需转换返回的对象:

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