Цель-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, который будет использоваться как с основными объектами данных, так и с простыми объектами ol' vanilla. Похоже, что "шум" имеет соответствующие классы #import протокол в их заголовке; было бы чище переслать объявление протокола & import в заголовке файл реализации, как я показал выше. Однако Xcode выдает предупреждение, когда делает это таким образом:

Cannot find protocol definition for 'ObjectProperties'

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

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

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

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

4   51  

4 ответа:

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

#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

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

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

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

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

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

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

@class Foo;

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