objective-c @class 与 #import
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/322597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
@class vs. #import
提问by Coocoo4Cocoa
It is to my understanding that one should use a forward-class declaration in the event ClassA needs to include a ClassB header, and ClassB needs to include a ClassA header to avoid any circular inclusions. I also understand that an #importis a simple ifndefso that an include only happens once.
据我了解,如果 ClassA 需要包含 ClassB 标头,而 ClassB 需要包含 ClassA 标头以避免任何循环包含,则应该使用前向类声明。我也明白 an#import很简单,ifndef所以包含只发生一次。
My inquiry is this: When does one use #importand when does one use @class? Sometimes if I use a @classdeclaration, I see a common compiler warning such as the following:
我的问题是:什么时候用#import,什么时候用@class?有时,如果我使用@class声明,我会看到一个常见的编译器警告,如下所示:
warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.
warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.
Would really love to understand this, versus just removing the @classforward-declaration and throwing an #importin to silence the warnings the compiler is giving me.
真的很想理解这一点,而不是仅仅删除@class前向声明并投入以消除#import编译器给我的警告。
回答by Ben Gottlieb
If you see this warning:
如果您看到此警告:
warning: receiver 'MyCoolClass' is a forward class and corresponding @interface may not exist
警告:接收器“MyCoolClass”是前向类,对应的@interface 可能不存在
you need to #importthe file, but you can do that in your implementation file (.m), and use the @classdeclaration in your header file.
您需要#import该文件,但您可以在实现文件 (.m) 中执行此操作,并使用@class头文件中的声明。
@classdoes not (usually) remove the need to #importfiles, it just moves the requirement down closer to where the information is useful.
@class不会(通常)消除对#import文件的需求,它只是将需求向下移动到更接近信息有用的地方。
For Example
例如
If you say @class MyCoolClass, the compiler knows that it may see something like:
如果你说@class MyCoolClass,编译器知道它可能会看到类似的东西:
MyCoolClass *myObject;
It doesn't have to worry about anything other than MyCoolClassis a valid class, and it should reserve room for a pointer to it (really, just a pointer). Thus, in your header, @classsuffices 90% of the time.
除了MyCoolClass是一个有效的类之外,它不必担心任何其他事情,它应该为指向它的指针(实际上,只是一个指针)保留空间。因此,在您的标题中,@class90% 的时间就足够了。
However, if you ever need to create or access myObject's members, you'll need to let the compiler know what those methods are. At this point (presumably in your implementation file), you'll need to #import "MyCoolClass.h", to tell the compiler additional information beyond just "this is a class".
但是,如果您需要创建或访问myObject的成员,则需要让编译器知道这些方法是什么。此时(大概在您的实现文件中),您需要#import "MyCoolClass.h"告诉编译器除了“这是一个类”之外的其他信息。
回答by PeyloW
Three simple rules:
三个简单的规则:
- Only
#importthe super class, and adopted protocols, in header files (.hfiles). #importall classes, and protocols, you send messages to in implementation (.mfiles).- Forward declarations for everything else.
- 只有
#import超类,以及采用的协议,在头文件(.hfiles)中。 #import所有类和协议,您在实现(.m文件)中发送消息。- 其他所有内容的前向声明。
If you do forward declaration in the implementation files, then you probably do something wrong.
如果您在实现文件中进行前向声明,那么您可能做错了什么。
回答by Abizern
Look at the Objective-C Programming Language documentation on ADC
查看关于ADC的 Objective-C 编程语言文档
Under the section on Defining a Class | Class Interface it describes why this is done:
在定义类部分下 | 类接口它描述了为什么这样做:
The @class directive minimizes the amount of code seen by the compiler and linker, and is therefore the simplest way to give a forward declaration of a class name. Being simple, it avoids potential problems that may come with importing files that import still other files. For example, if one class declares a statically typed instance variable of another class, and their two interface files import each other, neither class may compile correctly.
@class 指令最大限度地减少了编译器和链接器看到的代码量,因此是给出类名的前向声明的最简单方法。简单来说,它避免了导入文件而导入其他文件时可能出现的潜在问题。例如,如果一个类声明了另一个类的静态类型实例变量,并且它们的两个接口文件相互导入,则这两个类都无法正确编译。
I hope this helps.
我希望这有帮助。
回答by Marc Charbonneau
Use a forward declaration in the header file if needed, and #importthe header files for any classes you're using in the implementation. In other words, you always #importthe files you're using in your implementation, and if you need to reference a class in your header file use a forward declaration as well.
如果需要,请#import在头文件中使用前向声明,以及您在实现中使用的任何类的头文件。换句话说,你总是#import在你的实现中使用你正在使用的文件,如果你需要在你的头文件中引用一个类,也使用前向声明。
The exceptionto this is that you should #importa class or formal protocol you're inheriting from in your header file (in which case you wouldn't need to import it in the implementation).
在例外的情况是,你应该#import一类或正式协议,当您在你的头文件继承(在这种情况下,你不会需要导入它在执行)。
回答by Steph Thirion
The common practice is using @class in header files (but you still need to #import the superclass), and #import in implementation files. This will avoid any circular inclusions, and it just works.
通常的做法是在头文件中使用@class(但您仍然需要#import 超类),并在实现文件中使用#import。这将避免任何圆形夹杂物,它只是有效。
回答by vent
Another advantage: Quick compilation
另一个优点:快速编译
If you include a header file, any change in it causes the current file also to compile but this is not the case if the class name is included as @class name. Of course you will need to include the header in source file
如果包含头文件,则其中的任何更改都会导致当前文件也编译,但如果类名包含为@class name. 当然,您需要在源文件中包含头文件
回答by justin
My inquiry is this. When does one use #import and when does one use @class?
我的查询是这样的。什么时候使用#import,什么时候使用@class?
Simple answer: You #importor #includewhen there is a physical dependency. Otherwise, you use forward declarations (@class MONClass, struct MONStruct, @protocol MONProtocol).
简单的回答:你#import或#include当有身体依赖。否则,您使用前向声明 ( @class MONClass, struct MONStruct, @protocol MONProtocol)。
Here are some common examples of physical dependence:
以下是身体依赖的一些常见例子:
- Any C or C++ value (a pointer or reference is not a physical dependency). If you have a
CGPointas an ivar or property, the compiler will need to see the declaration ofCGPoint. - Your superclass.
- A method you use.
- 任何 C 或 C++ 值(指针或引用不是物理依赖项)。如果您将 a
CGPoint作为 ivar 或属性,则编译器将需要查看CGPoint. - 你的超类。
- 你使用的一种方法。
Sometimes if I use a @class declaration, I see a common compiler warning such as the following: "warning: receiver 'FooController' is a forward class and corresponding @interface may not exist."
有时,如果我使用 @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 #importproperly. 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.
编译器在这方面其实很宽容。它会丢弃提示(例如上面的提示),但是如果您忽略它们并且不#import正确,您可以轻松地丢弃您的堆栈。尽管它应该(IMO),但编译器不会强制执行此操作。在 ARC 中,编译器更加严格,因为它负责引用计数。发生的情况是编译器在遇到您调用的未知方法时退回到默认值。每个返回值和参数都假定为id. 因此,您应该消除代码库中的所有警告,因为这应该被视为物理依赖性。这类似于调用未声明的 C 函数。对于 C,假设参数为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).
您偏爱前向声明的原因是您可以按因素减少构建时间,因为依赖性最小。使用前向声明,编译器看到有一个名字,并且在没有物理依赖的情况下可以正确解析和编译程序,而无需看到类声明或其所有依赖。干净的构建需要更少的时间。增量构建花费的时间更少。当然,您最终会花费更多时间来确保您需要的所有标题对每个翻译都是可见的,但这可以快速缩短构建时间(假设您的项目不小)。
If you use #importor #includeinstead, you're throwing a lot more work at the compiler than is necessary. You're also introducing complex header dependencies. You can liken this to a brute-force algorithm. When you #import, you're dragging in tons of unnecessary information, which requires a lot of memory, disk I/O, and CPU to parse and compile the sources.
如果您使用#importor#include代替,则会在编译器上投入大量不必要的工作。您还引入了复杂的标头依赖项。您可以将其比作一种蛮力算法。当您使用 时#import,您会拖入大量不必要的信息,这需要大量内存、磁盘 I/O 和 CPU 来解析和编译源代码。
ObjC is pretty close to ideal for a C based language with regards to dependency because NSObjecttypes are never values -- NSObjecttypes 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.
ObjC 在依赖方面非常接近于基于 C 的语言的理想选择,因为NSObject类型从不是值——NSObject类型总是引用计数的指针。因此,如果您适当地构建程序的依赖项并在可能的情况下向前推进,则您可以摆脱令人难以置信的快速编译时间,因为几乎不需要物理依赖。您还可以在类扩展中声明属性以进一步减少依赖性。这对大型系统来说是一个巨大的好处——如果您曾经开发过大型 C++ 代码库,您就会知道它的不同之处。
Therefore, my recommendation is to use forwards where possible, and then to #importwhere there is physical dependence. If you see the warning or another which implies physical dependence -- fix them all. The fix is to #importin your implementation file.
因此,我的建议是尽可能使用远期,然后到#import有身体依赖的地方。如果您看到警告或其他暗示身体依赖的警告 - 修复它们。修复方法是#import在您的实现文件中。
As you build libraries, you will likely classify some interfaces as a group, in which case you would #importthat library where physical dependence is introduced (e.g. #import <AppKit/AppKit.h>). This can introduce dependence, but the library maintainers can often handle the physical dependencies for you as needed -- if they introduce a feature, they can minimize the impact it has on your builds.
当您构建库时,您可能会将某些接口归类为一个组,在这种情况下,您会将#import引入物理依赖性的那个库(例如#import <AppKit/AppKit.h>)。这可能会引入依赖,但库维护者通常可以根据需要为您处理物理依赖——如果他们引入了一个特性,他们可以最大限度地减少它对您的构建的影响。
回答by Bruce Goodwin
I see a lot of "Do it this way" but I don't see any answers to "Why?"
我看到很多“这样做”,但我没有看到“为什么?”的任何答案。
So: Whyshould you @class in your header and #import only in your implementation? You're doubling your work by having to @class and#import all the time. Unless you make use of inheritance. In which case you'll be #importing multiple times for a single @class. Then you have to remember to remove from multiple different files if you suddenly decide you don't need access to a declaration anymore.
所以:为什么你应该在你的头文件中使用 @class 而只在你的实现中使用 #import ?由于必须一直使用@class和#import,您的工作量加倍。除非你使用继承。在这种情况下,您将为单个@class 多次#importing。如果您突然决定不再需要访问声明,那么您必须记住从多个不同的文件中删除。
Importing the same file multiple times isn't an issue because of the nature of #import. Compiling performance isn't really an issue either. If it were, we wouldn't be #importing Cocoa/Cocoa.h or the like in pretty much every header file we have.
由于#import 的性质,多次导入同一个文件不是问题。编译性能也不是真正的问题。如果是这样,我们就不会在我们拥有的几乎每个头文件中使用 #importing Cocoa/Cocoa.h 或类似文件。
回答by Anshuman Mishra
if we do this
如果我们这样做
@interface Class_B : Class_A
mean we are inheriting the Class_A into Class_B, in Class_B we can access all the variables of class_A.
意味着我们将 Class_A 继承到 Class_B,在 Class_B 中我们可以访问 class_A 的所有变量。
if we are doing this
如果我们这样做
#import ....
@class Class_A
@interface Class_B
here we saying that we are using the Class_A in our program, but if we want to use the Class_A variables in Class_B we have to #import Class_A in .m file(make a object and use it's function and variables).
这里我们说我们在程序中使用了 Class_A,但是如果我们想在 Class_B 中使用 Class_A 变量,我们必须在 .m 文件中#import Class_A(创建一个对象并使用它的函数和变量)。
回答by Homam
for extra info about file dependencies & #import & @class check this out:
有关文件依赖项 & #import & @class 的额外信息,请查看:
http://qualitycoding.org/file-dependencies/itis good article
http://qualitycoding.org/file-dependencies/这是一篇好文章
summary of the article
文章摘要
imports in header files:
- #import the superclass you're inheriting, and the protocols you're implementing.
- Forward-declare everything else (unless it comes from a framework with a master header).
- Try to eliminate all other #imports.
- Declare protocols in their own headers to reduce dependencies.
- Too many forward declarations? You have a Large Class.
imports in implementation files:
- Eliminate cruft #imports that aren't used.
- If a method delegates to another object and returns what it gets back, try to forward-declare that object instead of #importing it.
- If including a module forces you to include level after level of successive dependencies, you may have a set of classes that wants to become a library. Build it as a separate library with a master header, so everything can be brought in as a single prebuilt chunk.
- Too many #imports? You have a Large Class.
在头文件中导入:
- #import 你继承的超类,以及你正在实现的协议。
- 前向声明其他所有内容(除非它来自具有主标头的框架)。
- 尝试消除所有其他#imports。
- 在自己的头文件中声明协议以减少依赖。
- 太多的前向声明?你有一个大班。
在实现文件中导入:
- 消除未使用的 cruft #imports。
- 如果一个方法委托给另一个对象并返回它返回的内容,请尝试向前声明该对象而不是 #importing 它。
- 如果包含一个模块迫使您逐级包含连续依赖项,那么您可能有一组想要成为库的类。将其构建为具有主标头的单独库,因此所有内容都可以作为单个预构建块引入。
- 太多#imports?你有一个大班。

