在 Objective-C 中前向声明枚举
Posted
技术标签:
【中文标题】在 Objective-C 中前向声明枚举【英文标题】:Forward-declare enum in Objective-C 【发布时间】:2010-10-31 02:18:22 【问题描述】:我在 Objective-C 程序中遇到枚举可见性问题。我有两个头文件,一个定义了typedef enum
。另一个文件需要使用typedef
'd 类型。
在直接 C 中,我会简单地 #include
另一个头文件,但在 Objective-C 中,建议不要在头文件之间使用 #import
,而是根据需要使用前向 @class
声明。但是,我不知道如何前向声明枚举类型。
我不需要实际的枚举值,除非在相应的.m
实现文件中,我可以安全地#import
离开。那么如何才能在标题中识别typedef enum
?
【问题讨论】:
【参考方案1】:继续使用#import
。人们建议尽可能使用@class
的唯一原因是因为它使您的代码编译速度稍快。但是,#import
从另一个 .h 文件中提取一个 .h 文件没有问题。事实上,你需要在扩展另一个类时这样做。
【讨论】:
在不使用#import 的情况下,上述方法是否可行?简单地做一个typedef int EnumName
怎么样?
我不这么认为。请参阅 gs 答案中的链接:***.com/questions/71416/…
人们建议使用@class 来避免#import 循环(其中 foo.h 导入 bar.h 和 bar.h 导入 foo.h)。在此处查看接受的答案:***.com/questions/9016478/…
更重要的是@class 保护您免受循环导入。
#import 对于来自 C/C++ 背景的人来说是 include-guard 安全的。【参考方案2】:
无论如何,您必须要么#import
他们要么创建一个单独的头文件,只包含typedef
。在头文件中不导入头文件会使编译速度更快,但不会改变任何其他内容。
Why doesn't C++ support forward declaration of enums?
【讨论】:
【参考方案3】:你的问题的答案是要么继续导入 typedef 头文件,要么使用像 NSInteger 这样的泛型类型而不是枚举类型。
但是,不导入头文件的原因不仅仅是编译速度。
不导入头文件还可以减少对无关类的无意访问。
例如,假设您有一个 TrackFileChanges 类来跟踪文件系统对特定文件的更改,并且您有一个 CachedFile 类来存储文件中的缓存数据。后者可能使用 TrackFileChanges* 类型的私有 ivar,但对于 CachedFile 的使用,这只是一个实现细节(理想情况下,ivar 将使用新的运行时使用私有属性自动生成,但如果你'重新使用旧的运行时)。
因此,#import "CachedFile.h" 的客户端可能不需要或不想访问 TrackFileChanges.h。如果他们这样做了,他们应该自己通过#importing 来明确说明。通过在 CachedFile.h 中使用 @class TrackFileChanges instea of #import "TrackFileChanges.h" 可以改进封装。
但话虽如此,如果第二个头文件想要将第一个头文件公开给所有客户端,那么从第二个头文件导入头文件并没有错。例如,声明类的头文件需要在子类化头文件中直接导入,而声明协议的头文件可能会直接导入(尽管您可以使用@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;
(不是编译器扩展)。
【讨论】:
您可以将此答案简化为:typedef enum Enum Enum;
然后只需在您的方法定义和声明中使用 Enum。【参考方案5】:
在 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 */`
【讨论】:
我昨天才开始将 typedef NS_ENUM 作为清理旧的 Objective C 代码的一种方法——这个答案对我有用。 @lal,这对 int 变量非常有用。我刚刚发布了一个关于如何将 typedef 枚举用于浮点变量的问题。希望你能回答 - ***.com/q/44233973/2348597 这应该是枚举前向声明的公认答案 你救了我的命。 如果您在 Swift 中定义@objc enum
并且需要在 .h
文件中使用该类型,这也很有帮助。您必须以这种方式转发声明它(查看您的 -Swift.h
标头以查看原始类型应该是什么)【参考方案6】:
对我来说,在 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。
【讨论】:
以上是关于在 Objective-C 中前向声明枚举的主要内容,如果未能解决你的问题,请参考以下文章
在 libc++ 的内联命名空间中前向声明类的可移植方式是啥?