Почему Xcode не предоставляет автозаполнение для точечных свойств объектов типа id <protocol>?

Учитывая это определение протокола:

@protocol MyProtocol <NSObject>
@property (nonatomic, strong) NSString *someProperty;
@end

Почему Xcode с радостью предложит автозаполнение для этого утверждения:

id<MyProtocol> thing = [ThingManager currentThing];
[thing someProperty]; // Xcode offered autocompletion here

Но он не предлагает автозаполнение, когда я пытаюсь получить доступ к одному и тому же свойству с помощью точечной нотации:

id<MyProtocol> thing = [ThingManager currentThing];
thing.someProperty; // Xcode claimed there were 
                    // "No completions" available
                    // after the period

Ответ 1

Поскольку id является базовым типом, Xcode и CLANG не уверены в предоставлении доступа к точечно-синтаксическому сигналу против него, потому что точечный синтаксис является просто синтаксическим сахаром для вызова метода связанному сетевому устройству или получателю в обычном объекте, но id имеет нет определенных членов метода. Глядя на это со стороны C, id - это typedef для указателя структуры, который компилятор не может видеть в своих членах, что означает, что он не может получить к ним доступ (не обращая внимания на то, что вам нужно будет разыменовать id до того, как dot-access будет сделать какой-либо смысловой смысл).

Возвращаясь к Objective-C сторонам, протоколы фактически не добавляют методы или свойства классам, которые утверждают, что их реализуют, скорее они служат в качестве спецификатора для других классов, которые реализуют объект, соответствующий данному протоколу ряд методов. Что касается завершения синтаксиса метода, Xcode объединяет все указанные методы всех файлов, импортированных в данный файл .m, потому что объект идентификатора типа может получать любое сообщение *

* , конечно, он может получить сообщение, но он все равно будет сбой, если он не реализован.

Ответ 2

Это своего рода тангенциальный ответ и мысленный эксперимент.

Но до этого я буду замечать, что вы можете получить автозаполнение свойства, пропустив id, например:

NSObject<MyProtocol> *thing;
thing.▮

Но если вы не хотите, чтобы весь список методов NSObject завершал ваше завершение, вы могли бы сделать что-то вроде

EmptyClass<MyProtocol> *thing = [ThingManager currentThing];

// completion list will be (close) to only the protocol props
thing.▮

EmptyClass служит аналогичный "OK, no promises!". роль, которую выполняет id, но автозаполнение нравится. Здесь EmptyClass:

NS_ROOT_CLASS
@interface EmptyClass

@end

@implementation EmptyClass

+ (void)initialize {} // required

@end

Помните, что объект в thing на самом деле не внедрен на EmptyClass (не может быть), поэтому это высокий fakery. Тем не менее, он

  • значительно недооценивает то, что действительно может сделать thing.
  • не (не может!) создает экземпляр объекта EmptyClass.

Так почему бы и нет? Если вы попытаетесь сделать это очень сложно, вы можете вызвать такие проблемы, как

EmptyClass *nooooo = [[NSClassFromString(@"EmptyClass") alloc] init];

который будет немедленно исключать. Но на самом деле это не сложная ошибка.

Я не удивлю меня, но я не знаю этого сейчас. Пожалуйста, оставьте комментарий, если вы это сделаете.