在Objective-C中向前声明枚举


71

我在Objective-C程序中的枚举可见性遇到麻烦。我有两个头文件,一个头文件定义了一个typedef enum。另一个文件需要使用typedef'd类型。

在直接C语言中,我将只是#include另一个头文件,但是在Objective-C中,建议不要#import在头文件之间使用,而是@class根据需要使用前向声明。但是,我不知道如何前向声明枚举类型。

我不需要实际的枚举值,除了在相应的.m实现文件中,可以放心使用#import。那么,如何typedef enum在标头中识别它?

Answers:


10

继续使用#import。人们建议尽可能使用的唯一原因@class是因为它会使您的代码编译速度稍快一些。但是,#import从另一个文件中获取一个.h文件没有问题。实际上,在扩展另一个类时,您需要这样做。


1
没有使用#import,以上方法是否可行?简单地做一个typedef int EnumName怎么样?
Stephen Touset 09年

1
我不这么认为。请参阅gs答案中的链接:stackoverflow.com/questions/71416/…–
塞巴斯蒂安·塞利斯

37
人们建议使用@class避免#import循环(其中foo.h导入bar.h和bar.h导入foo.h)。看到这里接受的答案:stackoverflow.com/questions/9016478/...
alexkent

6
更重要的是,@class保护您免受循环导入的影响。
ozgur 2014年

3
#import对于包含C / C ++背景的用户来说是include-guard安全的。
MattD

62

在Objective-c中向前声明枚举(NS_ENUM / NS_OPTION)的最新方法(Swift 3; 2017年5月)是使用以下方法:

// 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
直到昨天我才开始使用typedef NS_ENUM来清理旧的Objective C代码-这个答案对我有用。
格雷格

@lal,这对于int变量非常有用。我刚刚发布了一个有关如何对浮点变量使用typedef枚举的问题。希望您能够回答它-stackoverflow.com/q/44233973/2348597
Greg,

3
这应该是枚举向前声明的公认答案
RubenVot

1
你救了我的命。
DawnSong

如果您@objc enum在Swift中定义,并且需要在.h文件中使用该类型,这也将很有帮助。您必须以这种方式转发声明(查看-Swift.h标头以查看原始类型)
Max

15

您问题的答案是继续导入typedef头文件,或者使用NSInteger之类的通用类型而不是枚举类型。

但是,除了编译速度之外,还有更多的原因不导入头文件。

不导入头文件还可以减少对无关类的无意访问。

例如,假设您有一个TrackFileChanges类,该类跟踪文件系统对特定文件的更改,而您有一个CachedFile类,用于存储文件中的缓存数据。后者可能使用TrackFileChanges *类型的私有ivar,但是对于CachedFile的使用,这只是一个实现细节(理想情况下,将使用新的运行时使用私有属性自动生成ivar,但是如果您这样做,重新使用旧的运行时间)。

因此,#import“ CachedFile.h”的客户端可能不需要或不想访问TrackFileChanges.h。如果这样做的话,他们应该自己#import使其清楚。通过在CachedFile.h中使用#import“ TrackFileChanges.h”的@class TrackFileChanges插件,可以改善封装效果。

但是,所有这些都说明,如果第二个头文件希望将第一个头文件公开给所有客户端,则从第二个头文件导入头文件没有错。例如,声明类的头文件需要直接导入子类化的头文件中,而声明协议的头文件则很可能直接导入(尽管您可以使用@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。
桑迪查普曼2014年

2

在Objective C .h文件中对我进行枚举的前向声明的工作是在ProjectName-Swift.h文件中查找并查看其内容,恰好是以下内容:

枚举SwiftEnumName:NSInteger;

我需要此前向声明,因为我的函数参数类型为SwiftEnumName。而且这也不允许我将ProjectName-Swift.h导入放入Objective C .h文件中。

然后在Objective C .m文件中,我只包含#import“ ProjectName-Swift.h”,并正常使用SwiftEnum。

这是使用Swift 4.1.2。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.