Objective-C中的#import和#include有什么区别?

Rya*_*ill 382 import objective-c include

在Objective-C中#import和#include之间有什么区别,有时候你应该使用一个而不是另一个吗?一个被弃用了吗?

我正在阅读以下教程:http://www.otierney.net/objective-c.html#preamble及其关于#import和#include的段落似乎自相矛盾或者至少不清楚.

Sve*_*ven 350

关于预处理器似乎有很多混乱.

当编译器看到#include它用所包含文件的内容替换该行时,编译器会做什么,没有问题.

所以如果你有一个a.h包含这个内容的文件:

typedef int my_number;
Run Code Online (Sandbox Code Playgroud)

b.c包含此内容的文件:

#include "a.h"
#include "a.h"
Run Code Online (Sandbox Code Playgroud)

b.c在编译之前,预处理器将翻译该文件

typedef int my_number;
typedef int my_number;
Run Code Online (Sandbox Code Playgroud)

这将导致编译器错误,因为类型my_number定义了两次.即使定义相同,C语言也不允许这样做.

由于头部经常在多个地方使用包括警卫通常在C.使用这看起来是这样的:

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif
Run Code Online (Sandbox Code Playgroud)

b.c在预处理之后,文件仍然会将标题的全部内容放入其中两次.但是第二个实例将被忽略,因为宏_a_h_included_已经被定义了.

这非常有效,但有两个缺点.首先必须编写包含警戒,并且每个标题中的宏名称必须不同.其次,编译器仍然需要查找头文件并按原样读取它.

Objective-C有#import预处理器指令(它也可以用于C和C++代码以及一些编译器和选项).这几乎#include与之相同,但它也在内部记录了哪些文件已被包含在内.该#import行仅在遇到第一次时被命名文件的内容替换.之后每次都被忽略了.

  • 在7000行模板头文件中将4`#include`s更改为`#import`s后,在编译和XCode intellisense响应性方面有显着的性能提升.(我不认为我在想象) (4认同)
  • 这是比接受的答案更好的答案.@Guill,你应该改变接受的答案. (3认同)

Jas*_*oco 338

#import指令作为#include的改进版本添加到Objective-C中.然而,它是否得到改善仍然是一个争论的问题.#import确保文件只被包含一次,这样你就不会遇到递归包含问题.但是,大多数体面的头文件都可以保护自己不受此影响,所以它并没有那么大的好处.

基本上,由您决定要使用哪个.我倾向于#import标头用于Objective-C事物(比如类定义等)和#include标准C我需要的东西.例如,我的一个源文件可能如下所示:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>
Run Code Online (Sandbox Code Playgroud)

  • 即使头文件包含包含保护,如果使用#include,在编译期间仍会有性能损失 - 编译器必须打开每个头文件以注意包含保护. (60认同)
  • @dave - #import是预处理器的Objective-C添加.GCC也支持它在C和C++源文件中,尽管他们官方建议不要在C或C++中使用它,而是支持便携式传统的标头保护.但是,所有Objective-C预处理器都必须包含#import. (32认同)
  • 标题后卫是你添加到顶部的地方:`#ifndef myheader #define myheader` ...后跟标题代码......`#endif` (13认同)
  • 我认为#import实际上是GCC的补充,而不是Objective-C.只要用GCC(或Clang)编译,就可以在非ObjC语言中使用它 (7认同)
  • 标头保护是一个预处理器指令,可确保标头仅在源文件中包含一次. (4认同)
  • 在一个不错的编译器上,include guard不会在编译时花费.如果要使用头文件,则需要包含一次头文件.当它包含在内时,编译器将检测到头部保护.并记住它.在同一文件的第二个#include上,编译器知道头文件保护,甚至不查看该文件. (3认同)
  • 这不是标准与非标准; 它是语言与语言,一种是另一种意图.如果您正在使用Objective-C**和**,您打算*包含Objective-C标头*,请使用#import.如果您正在使用C,C++**或**正在使用Objective-C并且只想在另一个文件中内联一个文件,请使用#include. (3认同)
  • 什么是头球卫士? (2认同)
  • 所以官方的建议是避免使用更新,更简单,更好的东西,以保持与旧版本的兼容性,这些东西可以很容易地更新以支持新关键字?那是胡说八道.有人需要引进一些新官员. (2认同)
  • @aroth:这不是关于新的与旧的.这是关于标准与非标准的关系. (2认同)
  • @Chuck-也许吧。但是,我认为,一个不会发展的标准,推荐过时,笨拙和过时的做事方式,并不是很有价值。尤其是当工具的功能不断发展时,甚至在“所有的Objective-C预处理程序都必须包含#import”时以及当我们在Objective-C项目的上下文中讨论代码时,其发展都是如此。 (2认同)
  • 这里似乎没有人提到“#import”的一个好处,那就是它是唯一不需要额外代码的解决方案。无论哪种方式,代码都不多,但同一件事的代码越少通常是最好的。还稍微降低了新开发人员的门槛,他们可能不知道头防护或“#pragma Once”。 (2认同)

小智 61

我同意杰森的观点.

我抓到了这样做:

#import <sys/time.h>  // to use gettimeofday() function
#import <time.h>      // to use time() function
Run Code Online (Sandbox Code Playgroud)

对于GNU gcc,它一直抱怨没有定义time()函数.

然后我将#import改为#include,一切顺利.

原因:

#import <sys/time.h>:
    <sys/time.h>仅包含<time.h> 的一部分,使用#defines

你#import <time.h>:
    不行.尽管只包含<time.h>的一部分,但
    就#import而言,该文件现已完全包含在内.

底线:

C/C++传统上标头包括部件的其他包含文件.
因此,对于C/C++标头,请使用#include.
对于objc/objc ++标头,请使用#import.

  • 似乎 clang 没有这个未定义的问题。 (2认同)

Fer*_*cio 22

#include像C一样工作#include.

#import跟踪已包含哪些标头,如果在编译单元中多次导入标头,则会忽略这些标头.这使得不必使用标题保护.

底线只是#import在Objective-C中使用,如果您的标题最终导入不止一次,请不要担心.

  • 假装我不熟悉C#include(主要是因为我不是),#include和#import之间的主要区别是什么?另外,你能告诉我头盔是什么吗? (2认同)

Ale*_*ray 13

我知道这个线程很老......但是在"现代"......通过clang的@import模块有一个更优越的"包含策略" - 这是经常被忽视的..

模块通过用更健壮,更有效的语义模型替换文本预处理器包含模型来改进对软件库API的访问.从用户的角度来看,代码看起来只是略有不同,因为一个使用导入声明而不是#include预处理器指令:

@import Darwin; // Like including all of /usr/include. @see /usr/include/module.map
Run Code Online (Sandbox Code Playgroud)

要么

@import Foundation;  //  Like #import <Foundation/Foundation.h>
@import ObjectiveC;  //  Like #import <objc/runtime.h>
Run Code Online (Sandbox Code Playgroud)

但是,此模块导入的行为与相应的#include完全不同:当编译器看到上面的模块导入时,它会加载模块的二进制表示,并使其API直接可供应用程序使用.导入声明之前的预处理程序定义对提供的API没有影响...因为模块本身被编译为单独的独立模块.此外,导入模块时将自动提供使用该模块所需的任何链接器标志.此语义导入模型解决了预处理器包含模型的许多问题.

要启用模块,传递命令行标志-fmodules又名CLANG_ENABLE_MODULESXcode-在编译时.如上所述..这种策略可以避免任何和所有LDFLAGS.在中,您可以删除任何"OTHER_LDFLAGS"设置,以及任何"链接"阶段.

在此输入图像描述

我发现编译/启动时间"感觉"更加快速(或者可能,"链接"时只有较少的延迟?)..而且,提供了清除现在无关的Project-Prefix.pch文件的绝佳机会,以及相应的构建设置GCC_INCREASE_PRECOMPILED_HEADER_SHARING,GCC_PRECOMPILE_PREFIX_HEADER以及GCC_PREFIX_HEADER

此外,虽然没有详细记录......您可以module.map为自己的框架创建s并以相同的方式包含它们. 你可以看看我的ObjC-Clang-Modules github repo,了解如何实现这些奇迹的一些例子.


Evo*_*ate 5

如果您熟悉 C++ 和宏,那么

#import "Class.h" 
Run Code Online (Sandbox Code Playgroud)

类似于

{
#pragma once

#include "class.h"
}
Run Code Online (Sandbox Code Playgroud)

这意味着当您的应用程序运行时,您的类只会加载一次。