@class vs. #import
据我所知,如果class a需要包含classb头,而classb需要包含classa头,则应该使用forward类声明,以避免任何循环包含。我也理解,
我的问题是:什么时候用
warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.
我真的很想理解这一点,而不仅仅是删除
如果看到此警告:
warning: receiver 'MyCoolClass' is a forward class and corresponding @interface may not exist
您需要
例如
如果您说
1 | MyCoolClass *myObject; |
除了
但是,如果需要创建或访问
三条简单规则:
- 在头文件(
.h 文件)中,只有超级类#import 和采用的协议。 #import 所有类和协议,您将消息发送到正在实现的(.m 文件)。- 转发其他所有内容的声明。
如果您在实现文件中进行了转发声明,那么您可能会出错。
查看ADC上的Objective-C编程语言文档
在"定义类类接口"一节中,它描述了为什么要这样做:
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.
我希望这有帮助。
如果需要,在头文件中使用forward声明,在实现中使用的任何类的头文件中使用
例外情况是您应该在头文件中继承一个类或正式协议(在这种情况下,您不需要在实现中导入它)。
通常的做法是在头文件中使用@class(但仍然需要导入超类),并在实现文件中导入。这样可以避免任何圆形的杂质,而且它只是起作用。
另一个优势:快速编译
如果包含头文件,其中的任何更改都会导致当前文件也被编译,但如果类名包含为
My inquiry is this. When does one use #import and when does one use @class?
简单的回答:当存在物理依赖关系时,您使用
以下是物理依赖的一些常见例子:
- 任何C或C++值(指针或引用不是物理依赖项)。如果您将
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."
编译器在这方面实际上非常宽容。它将删除提示(如上面的提示),但如果您忽略了它们,并且不正确地执行
您倾向于向前声明的原因是,您可以通过因子减少构建时间,因为存在最小的依赖性。使用forward声明,编译器可以看到有一个名称,并且在没有物理依赖关系的情况下,可以正确地分析和编译程序,而不必看到类声明或其所有依赖关系。干净的建筑需要更少的时间。增量构建花费的时间更少。当然,您最终会花费更多的时间来确保您所需要的所有头文件对每个翻译都是可见的,但是这会在缩短构建时间(假设您的项目不是很小)中很快得到回报。
如果您使用
objc对于基于C语言的依赖关系非常理想,因为
因此,我的建议是在可能的情况下使用远期,然后在存在物理依赖的情况下使用
当您构建库时,您可能会将一些接口分类为一个组,在这种情况下,您将
我看到很多"这样做",但我看不到"为什么?"
那么:为什么要在头中@class,并且只在实现中导入?你的工作翻了一番,因为你一直需要@class和导入。除非你利用遗产。在这种情况下,您将为一个@class导入多次。如果突然决定不再需要访问声明,那么必须记住从多个不同的文件中删除。
由于导入的性质,多次导入同一文件不是问题。编译性能也不是真正的问题。如果是这样的话,我们就不会在几乎所有的头文件中导入coco/coco.h或类似的文件。
如果我们这样做
1 | @interface Class_B : Class_A |
也就是说,我们将类_a继承到类_b中,在类_b中,我们可以访问类_a的所有变量。
如果我们这样做
1 2 3 | #import .... @class Class_A @interface Class_B |
这里我们说我们在程序中使用了class_a,但是如果我们想在class_b中使用class_a变量,我们必须在.m文件中导入class_a(创建一个对象并使用它的函数和变量)。
有关文件依赖项的额外信息,请查看:
http://qualitycoding.org/file-dependencies/这是好东西
文章摘要
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.
如果您试图在头文件中声明一个尚未导入的变量或属性,则会出现一个错误,说明编译器不知道该类。
你的第一个想法可能是
在某些情况下,这可能会导致问题。
例如,如果您在头文件、结构或类似的东西中实现了一组C方法,因为它们不应该被多次导入。
因此,您可以用
I know you don't know that class, but it exists. It's going to be imported or implemented elsewhere
它基本上告诉编译器关闭并编译,即使它不确定这个类是否会被实现。
通常在.m文件中使用
当我成长的时候,我心里只有三件事不会给我带来任何问题。
对于所有其他类(我的项目中的子类和子类),我通过forward类声明它们。
把@class想象成告诉编译器"相信我,这存在"。
将导入视为复制粘贴。
出于多种原因,您希望最小化导入的数量。如果不进行任何研究,首先想到的是它可以缩短编译时间。
注意,当您从类继承时,不能简单地使用forward声明。您需要导入文件,这样您声明的类就知道它是如何定义的。
转发声明以防止编译器显示错误。
编译器将知道在头文件中有一个名为要声明的类。
只有当您以编译器需要知道其实现的方式使用该类时,编译器才会抱怨。
前任:
如果你只是用它作为指针,它不会抱怨。当然,您必须在实现文件中导入它(如果您正在实例化该类的对象),因为它需要知道类内容来实例化对象。
注意:导入与包含不同。这意味着没有所谓的循环导入。导入是一种要求编译器查找特定文件以获取某些信息的请求。如果该信息已经可用,编译器将忽略它。
试试这个,把A.H输入B.H,把B.H输入A.H。这样就不会有任何问题或投诉,而且也会很好地工作。
何时使用@class
只有当您甚至不想在标题中导入标题时,才使用@class。在这种情况下,你甚至不想知道那门课是什么。可能还没有该类的头的情况。
例如,您正在编写两个库。一个类名为a,存在于一个库中。此库包含来自第二个库的头。该头可能有一个指针,但可能不需要再次使用它。如果库1尚不可用,则如果使用@class,库B将不会被阻止。但如果您要导入a.h,则会阻止库2的进度。
这是一个示例场景,我们需要@class。
考虑一下,如果您希望在头文件中创建一个协议,它有一个数据类型相同的参数,那么您可以使用@class。请记住,您也可以单独声明协议,这只是一个例子。
1 2 3 4 5 6 7 8 9 10 | // DroneSearchField.h #import <UIKit/UIKit.h> @class DroneSearchField; @protocol DroneSearchFieldDelegate<UITextFieldDelegate> @optional - (void)DroneTextFieldButtonClicked:(DroneSearchField *)textField; @end @interface DroneSearchField : UITextField @end |