Почему синтаксис точки не может использоваться для метода, тип возвращаемого которого является instancetype?

Pretend У меня есть категория в 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 allocTemplate].name во время компиляции, если self является FDActor?

Я знаю, что это работает, если вы используете обычный синтаксис отправки сообщений, но я явно заинтересован в синтаксической ошибке точки.

Ответ 1

Казалось бы, что instancetype используется только для проверки типов во время назначения, поэтому FDActor *actor = [FDActor allocTemplate] не выдаст предупреждения.

Если мы применим возвращаемый тип allocTemplate, проблема исчезнет.

- (void)sayHi { ((__typeof__(self))[[self class] allocTemplate]).name; }

Но обратите внимание, что это работает только в методе экземпляра, так как тип экземпляра - это другой экземпляр. Обратите также внимание на то, что, поскольку мы теперь явно вводим возвращаемое значение, метод allocTemplate больше не нужен, если все искали, это проверка типа, тогда мы можем даже просто наложить нуль, и он будет работать.

Если мы пытаемся использовать одно и то же в методе класса, он не работает

+ (void)sayHi { ((__typeof__(self) *)[self allocTemplate]).name; } Это связано с тем, что (__typeof__(self) *) doers не оценивают значение FDActor *, но Class *, на которое ARC будет жаловаться. Похоже, что нет способа разрешить информацию типа FDActor * общим способом из метода класса во время компиляции.

Я предпочел бы, чтобы ключевое слово instancetype было немного более полезным.

Ответ 2

Сообщается об ошибке. [self allocTemplate] является id. Синтаксис свойств никогда не работает на id.

Обратите внимание, что это работает:

[FDActor allocTemplate].name;

Я думаю, что класс, к которому должен быть привязан instancetype, должен быть указан в вызове; иначе мы просто вернемся к id.

Ответ 3

Я возьму на это удар, с отказом от права, что я не совсем понимаю, как фактически реализована поддержка instancetype, не говоря уже о всех подробных подробностях системы проверки типа компилятора. Другими словами, это мое лучшее предположение, а не авторитетный или полный ответ...

После компиляции методы 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.