Переслать-объявить перечисление в Objective-C
У меня возникают проблемы с видимостью перечисления в программе Objective-C. У меня есть два файла заголовка, и один определяет typedef enum
. Другой файл должен использовать тип typedef
'd.
В прямом C я бы просто #include
другой заголовочный файл, но в Objective-C он рекомендовал не использовать #import
между заголовочными файлами, а вместо этого использовать форвардные объявления @class
по мере необходимости. Однако я не могу понять, как перенаправить объявление типа перечисления.
Мне не нужны фактические перечисляемые значения, кроме соответствующего файла реализации .m
, где я могу безопасно #import
прочь. Итак, как я могу получить typedef enum
для распознавания в заголовке?
Ответы
Ответ 1
Идем дальше и используем #import
. Единственная причина, по которой люди рекомендуют использовать @class
, когда это возможно, потому что это немного ускоряет компиляцию вашего кода. Тем не менее, нет проблемы с #import
с одним файлом .h из другого. Фактически, вам нужно сделать это, когда расширяете другой класс.
Ответ 2
Ответ на ваш вопрос заключается в том, чтобы либо перейти, либо импортировать заголовочный файл typedef, либо использовать общий тип, например NSInteger, вместо типа перечисления.
Однако есть больше причин не импортировать заголовочный файл, а просто компилировать скорость.
Не импортировать файл заголовка также уменьшает ваш непреднамеренный доступ к посторонним классам.
Например, скажем, у вас есть класс TrackFileChanges, который отслеживает файловую систему для изменений в конкретном файле, и у вас есть класс CachedFile, который хранит данные в кешированном файле. Последний может использовать частный ivar типа TrackFileChanges *, но для использования CachedFile это просто деталь реализации (в идеале, ivar будет автоматически генерироваться с помощью частного свойства с использованием новой среды выполнения, но это невозможно, повторное использование старого времени выполнения).
Таким образом, клиенты, которые #import "CachedFile.h", вероятно, не нуждаются или не хотят получить доступ к TrackFileChanges.h. И если они это сделают, они должны четко прояснить, #importing это самостоятельно. Используя @class TrackFileChanges instea #import "TrackFileChanges.h" в CachedFile.h, вы улучшаете инкапсуляцию.
Но все, что было сказано, ничего не связано с импортом файла заголовка из второго файла заголовка, если второй заголовок хочет разоблачить первый для всех клиентов. Например, заголовочные файлы, объявляющие классы, должны быть импортированы непосредственно в заголовочные файлы подкласса, а файлы заголовков, объявляющие протоколы, могут быть импортированы напрямую (хотя вы можете использовать @protocol ABC, чтобы избежать этого).
Ответ 3
Последний способ (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 */`
Ответ 4
Если вы в порядке используете расширения компилятора, вы можете использовать этот порядок в Clang:
enum Enum;
typedef enum Enum Enum2;
void f(Enum2); // ok. it sees this type true name.
enum Enum {
E_1
};
// ok. now its declaration is visible and we can use it.
void f(Enum2 e) {
}
Примечание. Это вызовет предупреждение -Wpedantic
.
Если вы используете С++ 11, вы должны использовать их перечисления, которые безопасны для пересылки объявления - например. enum class Enum:uint8_t;
(не расширение компилятора).
Ответ 5
В любом случае вам придется либо #import
, либо создать отдельный файл заголовка, содержащий только typedef
. Не импортирование файлов заголовков в заголовок делает компиляцию быстрее, но ничего не меняет.
Почему С++ не поддерживает форвардное объявление перечислений?