提问



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


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

最佳参考


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


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


#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>

其它参考1


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


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


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


typedef int my_number;


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


#include "a.h"
#include "a.h"


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


typedef int my_number;
typedef int my_number;


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


由于标题通常用于多个地方,因此通常在C中使用 include guards 。这看起来像这样:


 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif


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


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


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

其它参考2


我同意杰森的观点。


我抓到了这样做:


#import <sys/time.h>  // to use gettimeofday() function
#import <time.h>      // to use time() function


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


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


原因:


你#import< sys/time.h>:

&NBSP;&NBSP;&NBSP;&NBSP;< SYS/time.h中>仅包含< time.h>的部分通过使用#defines



你#import< time.h>:

    不去。即使只是< time.h>的一部分。已被包括在内,如同
    就#import而言,该文件现已包含完全



底线:


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

对于objc/objc ++标头,请使用#import。

其它参考3


#include就像C #include一样。


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


底线只是在Objective-C中使用#import,如果你的标题不止一次导入某些内容,请不要担心。

其它参考4


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



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



@import Darwin; // Like including all of /usr/include. @see /usr/include/module.map


要么


@import Foundation;  //  Like #import <Foundation/Foundation.h>
@import ObjectiveC;  //  Like #import <objc/runtime.h>



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



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





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


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

其它参考5


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


#import "Class.h" 


类似于


{
#pragma once

#include "class.h"
}


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

其它参考6


如果你在.h文件中#include一个文件两次比编译器会给出错误。
但是如果#import一个文件不止一次,编译器就会忽略它。

其它参考7


在可能的情况下,我的一个.h文件中有一个全局变量导致了问题,我通过在它前面添加extern来解决它。

其它参考8


#include它过去常常从另一个文件中获取东西到#include中使用的东西。
例如:


文件中的:main.cpp


#include "otherfile.h"

// some stuff here using otherfile.h objects,
// functions or classes declared inside


在每个头文件(* .h)的顶部使用标头防护,以防止包含同一个文件多一次(如果它发生,您将收到编译错误)。


文件中的:otherfile.h


#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif


即使您在代码中放入#includeotherfile.hn,也不会重新声明其中的内容。