Переслать-объявить перечисление в 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; (не расширение компилятора).