协慌网

登录 贡献 社区

@class 与 #import

据我了解,如果 ClassA 需要包括 ClassB 标头,而 ClassB 需要包括 ClassA 标头,以避免任何循环包含,则应使用前向类声明。我也理解#import是一个简单的ifndef因此一个 include 仅发生一次。

我的查询是:什么时候使用#import和什么时候使用@class ?有时,如果我使用@class声明,则会看到常见的编译器警告,例如:

warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.

真的很想了解这一点,而不是仅仅删除@class前向声明,并抛出#import来使编译器向我发出的警告静音。

答案

如果看到此警告:

警告:接收器 “MyCoolClass” 是转发类,并且相应的 @interface 可能不存在

您需要#import文件,但是可以在实现文件(.m)中执行此操作,并在头文件中@class

@class并不会(通常)消除对#import文件的需要,它只是将需求向下移到信息有用的地方。

例如

如果您说@class MyCoolClass ,则编译器知道它可能会看到类似以下内容的内容:

MyCoolClass *myObject;

MyCoolClass是有效的类之外,它不必担心其他任何事情,它应该为指向它的指针(实际上只是一个指针)保留空间。因此,在您的标头中, @class足以满足 90%的时间要求。

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

三个简单的规则:

  • #import将超类和采用的协议导入头文件( .h文件)中。
  • #import所有类和协议,您可以在实施中向其发送消息( .m文件)。
  • 转发其他声明。

如果在实现文件中进行前向声明,则可能做错了什么。

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

在 “定义类” 部分下 | 类接口描述了这样做的原因:

@class 指令最大程度地减少了编译器和链接器看到的代码量,因此是对类名进行前向声明的最简单方法。很简单,它避免了导入文件而又导入其他文件时可能出现的潜在问题。例如,如果一个类声明了另一个类的静态类型实例变量,并且它们的两个接口文件相互导入,则任何一个类都可能无法正确编译。

我希望这有帮助。