我的问题是这样的。什么时候使用#import,什么时候使用@class?
简单的回答:当存在物理依赖时,使用#import或#include。否则,使用正向声明(@class MONClass, struct MONStruct, @protocol MONProtocol)。
以下是一些常见的身体依赖的例子:
任何C或c++值(指针或引用不是物理依赖项)。如果您将CGPoint作为ivar或属性,编译器将需要看到CGPoint的声明。
你的超类。
你使用的方法。
有时如果我使用@class声明,我看到一个常见的编译器警告,如下所示:
“警告:接收端‘FooController’是转发类,对应的@interface可能不存在。”
The compiler's actually very lenient in this regard. It will drop hints (such as the one above), but you can trash your stack easily if you ignore them and don't #import properly. Although it should (IMO), the compiler does not enforce this. In ARC, the compiler is more strict because it is responsible for reference counting. What happens is the compiler falls back on a default when it encounters an unknown method which you call. Every return value and parameter is assumed to be id. Thus, you ought to eradicate every warning from your codebases because this should be considered physical dependence. This is analogous to calling a C function which is not declared. With C, parameters are assumed to be int.
The reason you would favor forward declarations is that you can reduce your build times by factors because there is minimal dependence. With forward declarations, the compiler sees there is a name, and can correctly parse and compile the program without seeing the class declaration or all of its dependencies when there is no physical dependency. Clean builds take less time. Incremental builds take less time. Sure, you will end up spending a little more time making sure the all the headers you need are visible to every translation as a consequence, but this pays off in reduced build times quickly (assuming your project is not tiny).
如果您使用#import或#include来代替,则会向编译器抛出大量不必要的工作。您还引入了复杂的头依赖项。你可以把它比作一个蛮力算法。当您使用#import时,会拖入大量不必要的信息,这需要大量内存、磁盘I/O和CPU来解析和编译源代码。
ObjC is pretty close to ideal for a C based language with regards to dependency because NSObject types are never values -- NSObject types are always reference counted pointers. So you can get away with incredibly fast compile times if you structure your program's dependencies appropriately and forward where possible because there is very little physical dependence required. You can also declare properties in the class extensions to further minimize dependence. That's a huge bonus for large systems -- you would know the difference it makes if you have ever developed a large C++ codebase.
因此,我的建议是尽可能使用forward,然后在有物理依赖的地方使用#import。如果您看到警告或其他暗示身体依赖的警告,请全部修复。修复方法是在实现文件中使用#import。
在构建库时,您可能会将一些接口分类为一组,在这种情况下,您将#导入引入物理依赖的库(例如#import <AppKit/AppKit.h>)。这可能会引入依赖关系,但是库维护者通常可以根据需要为您处理物理依赖关系——如果他们引入了一个特性,他们可以将其对构建的影响最小化。