Objective-C 中的前向声明枚举
我在 Objective-C 程序中的枚举可见性方面遇到问题。 我有两个头文件,其中一个定义了 typedef enum
。 另一个文件需要使用 typedef
的类型。
在直接 C 中,我会简单地 #include
另一个头文件,但在 Objective-C 中,建议不要在头文件之间使用 #import
,而是使用前向 @class
根据需要声明。 但是,我不知道如何转发声明枚举类型。
我不需要实际的枚举值,除了在相应的 .m
实现文件中,我可以安全地 #import
离开。 那么如何才能在标头中识别 typedef enum
呢?
I'm having trouble with enum visibility in an Objective-C program. I have two header files, and one defines a typedef enum
. Another file needs to use the typedef
'd type.
In straight C, I would simply #include
the other header file, but in Objective-C, it's recommended not to use #import
between header files, instead using forward @class
declarations as needed. However, I can't figure out how to forward-declare an enumeration type.
I don't need the actual enumerated values, except in the corresponding .m
implementation file, where I can safely #import
away. So how can I get the typedef enum
to be recognized in the header?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在 Objective-C 中转发声明枚举 (NS_ENUM/NS_OPTION) 的最新方法(Swift 3;2017 年 5 月)是使用以下内容:
Most recent way (Swift 3; May 2017) to forward declare the enum (NS_ENUM/NS_OPTION) in objective-c is to use the following:
您问题的答案是要么继续导入 typedef 头文件,要么使用 NSInteger 等泛型类型而不是枚举类型。
然而,不导入头文件的原因不仅仅是编译速度。
不导入头文件还可以减少对无关类的无意访问。
例如,假设您有一个 TrackFileChanges 类,用于跟踪文件系统中特定文件的更改,并且您有一个 CachedFile 类,用于存储文件中的缓存数据。 后者可能使用 TrackFileChanges* 类型的私有 ivar,但对于 CachedFile 的使用,这只是一个实现细节(理想情况下,ivar 将使用新的运行时使用私有属性自动生成,但如果您'正在使用旧的运行时)。
因此 #import "CachedFile.h" 的客户端可能不需要或不想访问 TrackFileChanges.h。 如果他们这样做,他们应该自己通过 #importing 来明确表示。 通过在 CachedFile.h 中使用 @class TrackFileChanges 代替 #import "TrackFileChanges.h",可以改进封装。
但话虽如此,如果第二个头文件想要将第一个头文件暴露给所有客户端,那么从第二个头文件导入头文件并没有什么问题。 例如,声明类的头文件需要直接在子类化头文件中导入,声明协议的头文件很可能直接导入(尽管您可以使用 @protocol ABC; 来避免这种情况)。
The answer to your question is to either go ahead and import the typedef header file or to use a generic type like NSInteger instead of the enum type.
However, there is more reason to not importing a header file than just compile speed.
Not importing a header file also reduces your inadvertent access to extraneous classes.
For example, say you have a TrackFileChanges class that tracks the file system for changes to a specific file, and you have a CachedFile class that stores cached data from a file. The latter might use a private ivar of type TrackFileChanges*, but for uses of CachedFile, this is simply an implementation detail (ideally, the ivar would be auto-generated with a private property using the new runtime, but thats not possible if you're using the old run time).
So clients that #import "CachedFile.h" probably do not need or want access to TrackFileChanges.h. And if they do, they should make it clear by #importing it themselves. By using @class TrackFileChanges instea of #import "TrackFileChanges.h" in CachedFile.h you improve the encapsulation.
But all that said, there is nothing awrong with importing a header file from a second header file if the second header wants to expose the first to all clients. For example, header files that declare classes need to be imported directly in subclassing header files, and header files declaring protocols might well be imported directly (although youy can use @protocol ABC; to avoid this).
继续使用
#import
。 人们建议尽可能使用@class
的唯一原因是它使代码的编译速度稍微快一些。 但是,从另一个 .h 文件#import
导入一个 .h 文件没有问题。 事实上,在扩展另一个类时您需要这样做。Go ahead and use
#import
. The only reason people recommend to use@class
when possible is because it makes your code slightly faster to compile. However, there is no issue with#import
ing one .h file from another. In fact, you need to do this when extending another class.如果您可以使用编译器扩展,则可以在 Clang 中使用以下顺序:
注意:它将触发
-Wpedantic
警告。如果您使用的是 C++11,则应该使用它们的枚举,它们可以安全地转发声明 - 例如
enum class Enum:uint8_t;
(不是编译器扩展)。If you are ok using compiler extensions, you could use this order in Clang:
Note: It will trigger a
-Wpedantic
warning.If you are using C++11, you should use their enums, which are safe to forward declare -- e.g.
enum class Enum:uint8_t;
(not a compiler extension).对我来说,在 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。
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.
无论如何,您都必须
#import
它们,或者创建一个仅包含typedef
的单独头文件。 不在标头中导入头文件会使编译速度更快,但不会改变其他任何内容。为什么 C++ 不支持枚举的前向声明?
You'd have to either
#import
them anyway or create a separate header file containing only thetypedef
. Not importing header files in a header makes the compilation faster, but doesn't change anything else.Why doesn't C++ support forward declaration of enums?