Подтвердить что ты не робот

Objective-C Заявки на пересылку протокола

ObjectProperties.h

@protocol ObjectProperties <NSObject>

@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSDate *date;
@property (assign, nonatomic) int64_t index;

@end

ClassA.h

#import <Foundation/Foundation.h>

@protocol ObjectProperties;

@interface ClassA : NSObject <ObjectProperties>

- (void)specialSauce;

@end;

ManagedClassA.h

#import <CoreData/CoreData.h>

@protocol ObjectProperties;

@interface ManagedClassA : NSManagedObject <ObjectProperties>

- (void)doSomething;

@end;

В приведенном выше примере кода я определил протокол в файле .h, который будет использоваться как с объектами Core Data, так и с обычными "ванильными объектами". Похоже, что "шум" имеет соответствующие классы #import протокол в заголовке; было бы проще отправить декларацию протокола и импортировать в файл реализации, как я показал выше. Тем не менее, Xcode выдает предупреждение при выполнении этого способа:

Cannot find protocol definition for 'ObjectProperties'

Код компилируется и в основном работает. Я говорю в основном потому, что некоторые функции с Core Data пытаются динамически создавать геттеры/сеттеры для свойства scalar, но я думаю, что, вероятно, потому, что я попал в кэш.

Конечно, наиболее очевидная работа заключается в том, чтобы просто импортировать заголовок протокола в заголовки классов.

Если мое понимание правильное (и мои знания очень недавно получены, и поэтому вполне возможно, что я ошибаюсь), если я импортирую протокол в заголовки своего класса и вношу изменения в протокол, то все последующие файлы что импортировать мои классы придется перекомпилировать.

Каков правильный способ решения этой проблемы?

4b9b3361

Ответ 1

Вы не можете переслать объявление суперкласса или протокола, которому он соответствует. В этих случаях вы должны включить заголовок. Это связано с тем, что (в случае суперкласса) переменные экземпляра и методы суперкласса становятся частью вашего класса; или (в случае протоколов) методы протокола становятся методами, объявленными в вашем классе, без необходимости явно их объявлять. (т.е. теперь другие люди, включившие ваш заголовок класса, увидят, что ваш класс объявляет эти методы, как если бы вы сами объявили их). Единственный способ, который может быть возможен, - это то, что они уже определены в этой области, т.е. импортируются их заголовки.

#import <SomeClass.h>
#import <SomeProtocol.h> // these two must be imported

@interface MyClass : SomeClass <SomeProtocol>
@end

Переменные декларации полезны для вещей, которые просто отображаются в типе переменной (в частности, переменной указателя объекта). Указатели объектов имеют одинаковый размер и нет разницы между различными типами указателей объектов во время выполнения (концепция типа указателя объекта - это всего лишь компиляция). Поэтому нет никакой реальной необходимости точно знать, что в классах этих типов. Таким образом, они могут быть объявлены вперед.

@class SomeClass;
@protocol SomeProtocol; // you can forward-declare these

@interface MyClass {
    SomeClass *var1;
    id<SomeProtocol> var2;
}
@end

Ответ 2

Да, вы правы, что все файлы необходимо перекомпилировать, но это необходимо. Файлы, импортирующие заголовок класса, должны знать методы, связанные с протоколом, который он реализует. Если вы уберете это определение в файле .m, тогда он будет виден только одному файлу (поскольку файлы .m никогда не импортируются). Это не то же самое, что переадресация классов. Если вы пересылаете объявление протокола, вы должны объявить его где-то, что видно в той же области, что и декларация. Я не могу придумать ни одного примера, где это не происходит в том же файле.

В ARC это ошибка, потому что ARC должна знать об управлении памятью объявленных методов (они возвращают +1 экземпляр, внутренние указатели и т.д.?)

Ответ 3

Объявив свой класс в MyClass.h, вы должны импортировать все файлы заголовков для своего суперкласса, а также протоколы, которые он принял в файле MyClass.h. Протоколы в Objective-c рассматриваются как вариант типа наследования.

Переменные объявления обычно используются в объявлении участника класса.

Ответ 4

Поскольку вы заявляете о соответствии протоколу, вы должны #import заголовок, содержащий протокол.

Это то же самое, что #importing суперкласс, а не forward, объявляющий его:

@class Foo;

@interface Bar : Foo
// Will get error: attempting to use the forward class 'Foo' as superclass of 'Bar'
@end;