2009-06-03 6 views
47

У меня возникают проблемы с видимостью перечисления в программе Objective-C. У меня есть два файла заголовка, и один определяет typedef enum. Другой файл должен использовать тип typedef 'd.Перемещение вперед-объявить в Objective-C

В прямой C, я бы просто #include другой файл заголовка, но в Objective-C, рекомендуется не использовать #import между файлами заголовков, используя вместо этого вперед @class декларации по мере необходимости. Однако я не могу понять, как перенаправить объявление типа перечисления.

Мне не нужны фактические перечисляемые значения, за исключением соответствующего файла реализации .m, где я могу безопасно #import. Итак, как я могу получить typedef enum для распознавания в заголовке?

+0

Для недавнего ответа (Swift 3, 2017) смотрите на мой ответ. http://stackoverflow.com/a/42009056/342794 – lal

ответ

18

Вперед и используйте #import. Единственная причина, по которой люди рекомендуют использовать @class, когда это возможно, потому что это делает ваш код немного более быстрым для компиляции. Тем не менее, нет проблемы с #import одним файлом .h из другого. Фактически, вам нужно сделать это, когда расширяете другой класс.

+1

Есть ли способ, которым это возможно, без использования #import? А как насчет просто 'typedef int EnumName'? –

+1

Я так не думаю. См. Ссылку в ответе gs: http://stackoverflow.com/questions/71416/forward-declaring-an-enum-in-c –

+0

С компиляцией #import требуется минуты, и в любом случае есть какая-то проводная вещь. –

0

В любом случае вам придется либо #import, либо создать отдельный файл заголовка, содержащий только typedef. Не импортирование файлов заголовков в заголовок делает компиляцию быстрее, но ничего не меняет.

Why doesn't C++ support forward declaration of enums?

16

Ответ на ваш вопрос либо идти вперед и импортировать файл заголовка ЬурейеГо или использовать общий тип, как NSInteger вместо перечислимого типа.

Однако есть больше причин не импортировать файл заголовка, а не просто компилировать скорость.

Не импортирование файла заголовка также снижает ваш непреднамеренный доступ к посторонним классам.

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

Таким образом, клиенты, которые #import "CachedFile.h", вероятно, не нуждаются или не хотят получить доступ к TrackFileChanges.h. И если они это сделают, они должны четко прояснить, #importing это самостоятельно. Используя @class TrackFileChanges instea #import «TrackFileChanges.h» в CachedFile.h, вы улучшаете инкапсуляцию.

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

4

Если вы нормально с помощью расширений компилятора, вы могли бы использовать этот порядок в Clang:

enum Enum; 
typedef enum Enum Enum2; 

void f(Enum2); // ok. it sees this type's true name. 

enum Enum { 
    E_1 
}; 

// ok. now its declaration is visible and we can use it. 

void f(Enum2 e) { 

} 

Примечание: Это вызовет -Wpedantic предупреждение.


Если вы используете C++ 11, вы должны использовать их перечисления, которые можно безопасно переадресовывать, - например. enum class Enum:uint8_t; (не расширение компилятора).

+1

Вы можете упростить этот ответ: 'typedef enum Enum Enum;' Тогда просто используйте Enum в определении и объявлении метода. –

15

Самых последний путь (Swift 3, май 2017) для пересылки объявить перечисление (NS_ENUM/NS_OPTION) в Objective-C является использование следующим:

// Forward declaration for XYZCharacterType in other header say XYZCharacter.h 
typedef NS_ENUM(NSUInteger, XYZCharacterType); 


// Enum declaration header: "XYZEnumType.h" 
#ifndef XYZCharacterType_h 
#define XYZCharacterType_h 

typedef NS_ENUM(NSUInteger, XYZEnumType) { 
    XYZCharacterTypeNotSet, 
    XYZCharacterTypeAgent, 
    XYZCharacterTypeKiller, 
}; 

#endif /* XYZCharacterType_h */` 
+1

работал для меня с быстрым 3 – stringRay2014

+3

В настоящее время это должен быть принятый ответ – citxx

+1

Я начал смотреть на typedef NS_ENUM только вчера, как способ очистить старый код Objective C - и этот ответ сработал для меня. – Greg

Смежные вопросы