为什么点语法不能用于返回类型为instancetype的方法?

时间:2014-04-04 14:51:34

标签: objective-c properties clang instancetype

假设我在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

我知道如果您使用普通的消息发送语法,但我对点语法错误明确感兴趣。

3 个答案:

答案 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上下文中检查可用方法与属性的区别(错误?)。