79

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

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

我不需要实际的枚举值,除非在相应的.m实现文件中,我可以安全地#import离开。那么我怎样才能typedef enum在标题中得到识别呢?

4

6 回答 6

73

在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 */`
于 2017-02-02T17:51:24.673 回答
16

您的问题的答案是继续导入 typedef 头文件,或者使用像 NSInteger 这样的泛型类型而不是 enum 类型。

但是,不导入头文件的原因不仅仅是编译速度。

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

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

因此,#import "CachedFile.h" 的客户端可能不需要或不想访问 TrackFileChanges.h。如果他们这样做了,他们应该自己通过#importing 来明确说明。通过在 CachedFile.h 中使用 @class TrackFileChanges instea of​​ #import "TrackFileChanges.h" 可以改进封装。

但话虽如此,如果第二个头文件想要将第一个头文件公开给所有客户端,那么从第二个头文件导入头文件并没有错。例如,声明类的头文件需要在子类化头文件中直接导入,而声明协议的头文件可能会直接导入(尽管您可以使用@protocol ABC;来避免这种情况)。

于 2009-06-04T03:17:52.847 回答
9

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

于 2009-06-03T18:56:47.180 回答
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;(不是编译器扩展)。

于 2013-08-08T01:33:38.137 回答
2

What worked for a forward declaration of an enum for me in an Objective C .h file was look in the ProjectName-Swift.h file and see what it put, which happened to be the following:

enum SwiftEnumName : NSInteger;

I needed this forward declaration because I had a function parameter type of SwiftEnumName. And it wouldn't let me put the ProjectName-Swift.h import in the Objective C .h file.

Then in the Objective C .m file I just had the #import "ProjectName-Swift.h" in it and just used the SwiftEnum normally.

This was using Swift 4.1.2.

于 2018-07-17T19:34:13.330 回答
-1

无论如何,您都必须使用#import它们,或者创建一个单独的头文件,其中仅包含typedef. 不在头文件中导入头文件会使编译速度更快,但不会改变任何其他内容。

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

于 2009-06-03T18:58:06.723 回答