我有一个简单的类层次结构,我的构造函数使用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
答案 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];
}