Objective-C中的前向声明枚举

Forward-declare enum in Objective-C

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

在纯C语言中,我只简单地将另一个头文件#include,但在目标C语言中,建议不要在头文件之间使用#import,而是根据需要使用forward @class声明。但是,我不知道如何转发声明枚举类型。

我不需要实际的枚举值,除非在相应的.m实现文件中,在该文件中我可以安全地将#import移出。那么,我如何才能在报头中识别typedef enum


最新的方法(Swift 3;2017年5月)在目标C中转发声明枚举(ns-enum/ns-u选项)是使用以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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 */`


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

但是,有更多的理由不导入头文件,而不仅仅是编译速度。

不导入头文件也会减少无意中访问无关类的次数。

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

因此,导入"cachedfile.h"的客户机可能不需要或不希望访问trackfilechanges.h。如果需要,他们应该通过自己导入来明确。通过在cachedfile.h中使用@class trackfilechanges instea of import"trackfilechanges.h",可以改进封装。

但是,尽管如此,如果第二个头文件希望向所有客户机公开第一个头文件,那么从第二个头文件导入头文件并不困难。例如,声明类的头文件需要直接导入到头文件的子类中,而声明协议的头文件也可以直接导入(尽管您可以使用@protocol abc;来避免这种情况)。


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


如果您可以使用编译器扩展,那么可以使用以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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,则应该使用它们的枚举,这些枚举是安全的向前声明的,例如EDCOX1×6 }(不是编译器扩展)。


在目标c.h文件中,为实现枚举的前向声明而工作的是在projectname swift.h文件中查找并查看它所放置的内容,结果如下:

枚举swiftenumname:nsinteger;

我需要这个forward声明,因为我有一个函数参数类型swiftenumname。它不会让我把项目名swift.h import放在目标c.h文件中。

然后,在目标C.M文件中,我只使用了import"projectname swift.h",并正常使用swiftenum。

使用的是Swift 4.1.2。


不管怎样,您都必须使用#import文件,或者创建一个只包含typedef的单独头文件。不在头中导入头文件会加快编译速度,但不会更改任何其他内容。

为什么C++不支持枚举的正向声明?