假设我在NSObject上有一个定义以下方法的类别:
+ (instancetype)allocTemplate
{
id instance = [self new];
return instance;
}
我有以下课程:
@interface FDActor : NSObject
@property (nonatomic, copy) NSString *name;
+ (void)sayHi;
@end
@implementation FDActor
+ (void)sayHi
{
[self allocTemplate].name;
}
@end
如果self是FDA的话,编译时如何出错[self allocTemplate].name
?
我知道如果您使用普通的消息发送语法,但我对点语法错误明确感兴趣。
答案 0 :(得分:3)
看起来好像instancetype仅用于在赋值期间进行类型检查,所以
FDActor *actor = [FDActor allocTemplate]
不会产生警告。
如果我们转换allocTemplate的返回类型,问题就会消失。
- (void)sayHi
{
((__typeof__(self))[[self class] allocTemplate]).name;
}
但请注意,这仅适用于实例方法,因为实例的类型是另一个实例。还要注意,因为我们现在显式地键入了返回值,所以不再需要allocTemplate方法,如果所有人都在寻找类型检查,那么我们甚至可以只运行nil并且它可以工作。
如果我们在类方法中尝试相同的事情,它就不起作用
+ (void)sayHi
{
((__typeof__(self) *)[self allocTemplate]).name;
}
这是因为(__typeof__(self) *)
执行者不会评估为FDActor *
,而是评估ARC会抱怨的Class *
。看起来无法在编译时从类方法中以通用方式解析类型信息FDActor *
。
我更希望instancetype
关键字更有用。
答案 1 :(得分:1)
错误消息告诉您。 [self allocTemplate]
是id
。属性语法 never 适用于id
。
请注意,此 工作:
[FDActor allocTemplate].name;
我认为必须在调用中指定与instancetype
相关的类;否则我们会回到id
。
答案 2 :(得分:0)
我会对此进行抨击,并且免责声明我不完全理解instancetype
支持是如何实际实现的,更不用说编译器的所有细节了。 s型检查系统。换句话说,这是我最好的猜测,而不是权威或完整的答案......
编译之后,Objective-C方法实际上是函数,其中self是函数的第一个参数,并且是类型id
。所以你有:
void sayHi(id self, SEL _cmd)
{
[self allocTemplate].name; // Actually calls to objc_msgSend, but that doesn't matter here
}
编译器对+allocTemplate
返回的值类型的处理似乎与此有关。如果您将self更改为显式FDActor
,则错误消失。当然,对于方法 - 而不是属性 - 编译器按照您的预期键入self
,并且会针对自身似乎没有响应的方法发出警告(或ARC下的错误)至。看起来这可能是编译器在instancetype
上下文中检查可用方法与属性的区别(错误?)。