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