根据我的理解,在ClassA需要包含ClassB标头,而ClassB需要包含ClassA标头以避免任何循环包含的情况下,应该使用前向类声明。我还理解#import是一个简单的ifndef,因此include只发生一次。

我的问题是:什么时候使用#import,什么时候使用@class?有时如果我使用@class声明,我看到一个常见的编译器警告,如下所示:

警告:接收端FooController是转发类,对应的@interface可能不存在。

我真的很想理解这一点,而不是仅仅删除@class forward-declaration并抛出一个#import来沉默编译器给我的警告。


当前回答

如果你看到这个警告:

警告:接收端MyCoolClass是转发类,对应的@interface可能不存在

您需要#导入文件,但是您可以在实现文件(.m)中这样做,并在头文件中使用@class声明。

@class并不(通常)消除#import文件的需要,它只是把需求移到更接近信息有用的地方。

例如

如果你说@class MyCoolClass,编译器知道它可能会看到类似这样的东西:

MyCoolClass *myObject;

除了MyCoolClass是一个有效的类之外,它不需要担心其他任何事情,并且它应该为指向它的指针保留空间(实际上,只是一个指针)。因此,在头文件中,@class占据了90%的时间。

然而,如果你需要创建或访问myObject的成员,你需要让编译器知道这些方法是什么。在这一点上(大概在你的实现文件中),你需要#import "MyCoolClass.h",告诉编译器除了"这是一个类"之外的其他信息。

其他回答

查看关于ADC的Objective-C编程语言文档

在定义类|类接口一节中,它描述了为什么这样做:

@class指令最大限度地减少了编译器和链接器看到的代码量,因此是给出类名正向声明的最简单方法。由于简单,它避免了导入仍然导入其他文件的文件时可能出现的潜在问题。例如,如果一个类声明了另一个类的静态类型实例变量,并且它们的两个接口文件相互导入,那么两个类都不能正确编译。

向前声明只是为了防止编译器显示错误。

编译器会知道你在头文件中声明的类的名称。

我看到很多“这样做”,但我没有看到任何“为什么”的答案。

那么:为什么在头文件中使用@class,而在实现中使用#import呢?一直使用@class和#import会使你的工作加倍。除非你使用继承。在这种情况下,您将为单个@class #import多次。然后,如果您突然决定不再需要访问某个声明,您必须记得从多个不同的文件中删除。

由于#import的性质,多次导入同一个文件不是问题。 编译性能也不是真正的问题。如果是的话,我们就不会在几乎每个头文件中都使用#importing Cocoa/Cocoa.h之类的代码了。

如果需要,在头文件中使用前向声明,并为在实现中使用的任何类导入头文件。换句话说,您总是#import您在实现中使用的文件,如果您需要在头文件中引用一个类,也可以使用forward声明。

例外的是,你应该在头文件中导入一个类或正式协议(在这种情况下,你不需要在实现中导入它)。

三个简单的规则:

只在头文件(.h文件)中#导入超类和采用的协议。 #导入所有类和协议,你发送消息到实现(。m文件)。 其他所有东西的前向声明。

如果在实现文件中进行前向声明,则可能会出错。