Objective-C 中的前向声明枚举

发布于 2024-07-23 21:56:42 字数 408 浏览 10 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

鲜肉鲜肉永远不皱 2024-07-30 21:56:42

在 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 */`

Most recent way (Swift 3; May 2017) to forward declare the enum (NS_ENUM/NS_OPTION) in objective-c is to use the following:

// 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 */`
打小就很酷 2024-07-30 21:56:42

您问题的答案是要么继续导入 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).

夜还是长夜 2024-07-30 21:56:42

继续使用#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 #importing one .h file from another. In fact, you need to do this when extending another class.

木槿暧夏七纪年 2024-07-30 21:56:42

如果您可以使用编译器扩展,则可以在 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; (不是编译器扩展)。

If you are ok using compiler extensions, you could use this order in 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) {

}

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).

甜扑 2024-07-30 21:56:42

对我来说,在 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.

红墙和绿瓦 2024-07-30 21:56:42

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

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

You'd have to either #import them anyway or create a separate header file containing only the typedef. 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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文