Переслать-объявить enum в Objective-C - PullRequest
63 голосов
/ 03 июня 2009

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

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

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

Ответы [ 6 ]

42 голосов
/ 02 февраля 2017

Самый последний способ (Swift 3; май 2017 г.) переслать объявление перечисления (NS_ENUM / NS_OPTION) в target-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 */`
15 голосов
/ 04 июня 2009

Ответ на ваш вопрос заключается в том, чтобы либо импортировать заголовочный файл typedef, либо использовать универсальный тип, такой как NSInteger, вместо типа enum.

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

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

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

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

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

13 голосов
/ 03 июня 2009

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

4 голосов
/ 08 августа 2013

Если вы в порядке, используя расширения компилятора, вы можете использовать этот порядок в 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 голос
/ 17 июля 2018

То, что сработало для предварительного объявления enum для меня в файле Objective C .h, было найдено в файле ProjectName-Swift.h и посмотрите, что он поместил, что оказалось следующим:

enum SwiftEnumName: NSInteger;

Мне нужно было это предварительное объявление, потому что у меня был тип параметра функции SwiftEnumName. И это не позволило бы мне поместить импорт ProjectName-Swift.h в файл Objective C .h.

Затем в файле Objective C .m у меня был только #import "ProjectName-Swift.h", и я просто использовал SwiftEnum как обычно.

При этом использовался Swift 4.1.2.

0 голосов
/ 03 июня 2009

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

Почему C ++ не поддерживает предварительное объявление перечислений?

...