在Objective-C中导入头文件

8
在Objective-C中,当我们在一个类中使用另一个类的对象时,按照惯例我们应该在.h文件中进行前向声明,即@class classname;。然后在.m文件中导入头文件,即#import "header.h"
但是,如果我们在.h文件中导入了头文件,那么在.m文件中就不需要再次导入。
这个惯例背后的原因是什么?哪种方式更有效呢?
5个回答

16

那么这个约定背后的原因是什么?

在可能的情况下,应该采用前向声明(@class MONClass;),因为编译器需要在使用之前知道typename是一个objc类,并且因为#import可能会拉入大量其他头文件(例如整个框架/库),严重扩展和复杂化您的依赖关系并增加构建时间。

哪种方法更有效?

采用前向声明。如果正确使用,你的构建、重新构建和索引速度会更快。


1
所以,为了澄清,如果我在.h文件中声明一个类型,我会使用@classname进行前向声明,然后在.m文件中向对象发送消息时,我会导入实际的头文件"classname.h"? - jim
@conor 正确。不过,还有一些细节:https://dev59.com/cnRC5IYBdhLWcg3wW_tk#9188603 过去几年中,编译器的进步和语言的变化(在ObjC中)使得将类的依赖关系保持在头文件之外变得更容易——在许多情况下,所有内容都可以放在*.m文件中。因此,您需要公开您的超类和任何协议。在这些情况下,您的实例变量和属性通常可以留在头文件之外——在这些情况下,不需要导入或前向声明。 - justin

4
您是正确的,将头文件导入.h中确实使得编程更加便捷(在短期内)。但是不建议这样做,而是应该在实现文件(.m)中导入它,以防止名称污染,即当有人导入您的头文件时,所有导入的头文件中的名称都可用。相反,只有导入您的头文件才应该导入您的函数/类,其余内容应在实现文件中导入。
此外,如果您在.h中导入头文件,则表示每个导入您的头文件的代码都必须在第三方头文件更改时重新编译,即使您的头文件明确没有更改。前向声明避免了这个问题,并且只强制那些实际使用第三方头文件的实现(.m)文件被重新编译。

2
尽管使用 .m 文件导入文件可以轻松地编写少量代码,但一般认为导入可能会影响加载时间和响应时间,确实会受到影响,也不会受到影响。因为根据苹果的文档:如果您担心包含主头文件会导致程序膨胀,请不用担心。因为 Mac OS X 接口是使用框架实现的,这些接口的代码驻留在动态共享库中而不是您的可执行文件中。此外,仅在运行时加载您程序使用的代码,因此您的内存占用量同样保持较小。至于在编译过程中包含大量头文件,同样不用担心。Xcode 提供了预编译头文件功能以加速编译时间。通过一次编译所有框架头文件,除非添加新框架,否则无需重新编译头文件。同时,您可以使用任何包含的框架接口而几乎不会有性能损失。因此,响应时间和加载时间只会在第一次受到影响,但无论如何,应该优先采用前向引用来保持编码标准并避免开销,即使很小 :)。

0

#import 是一个预处理器指令,它在编译器看到文件之前对文件进行操作。每当你感到困惑时,从概念上来看,它就像是复制和粘贴:当你看到 #import foo 时,这意味着文件 foo 的内容被插入到该点。(它比这更聪明一些,因为它还防止了重复包含)。

所以如果在 Bar.h 中有引用 Foo.h 的声明,那么你就需要在 Bar.h#import Foo.h。如果在 Bar.h 中没有使用 Foo,但是有 Bar.m,那么导入就放在 Bar.m 中。只在需要的地方保留声明。


-1

这只是告诉编译器我们有一个名为xx的类,如果你使用@class xx;

因为你现在不需要它的属性/方法。

而在下一个情况中,你也需要属性和方法,因为你将要访问它们。如果你在.h文件中使用@class xx并且不导入xx.h,那么声明xx对象将不会生成错误,但访问它的方法将生成警告,访问属性将生成错误。


4
抱歉我需要先确认,您需要对以下句子进行翻译:“I hate to be harsh, but your answer would be much easier to read (and thus to vote on) if you used capitals at the beginning of sentences and didn't use nonstandard abbreviations/spellings like 'becz', 'cz', and 'rite'.” - echristopherson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接