在Objective-C中,#import和#include之间有什么区别?在某些情况下,您应该一并使用?被弃用了吗?
我正在阅读以下教程:http : //www.otierney.net/objective-c.html#preamble及其有关#import和#include的段落似乎相矛盾,或者至少不清楚。
在Objective-C中,#import和#include之间有什么区别?在某些情况下,您应该一并使用?被弃用了吗?
我正在阅读以下教程:http : //www.otierney.net/objective-c.html#preamble及其有关#import和#include的段落似乎相矛盾,或者至少不清楚。
Answers:
#import指令已作为#include的改进版本添加到了Objective-C。但是,是否进行改进仍是一个有争议的问题。#import确保文件只包含一次,因此您不会遇到递归包含的问题。但是,大多数不错的头文件仍然可以防止这种情况的发生,因此,实际上并没有太大的好处。
基本上,由您决定要使用哪个。我倾向于#import Objective-C事物的标题(例如类定义之类),并#include我需要的标准C事物。例如,我的一个源文件可能如下所示:
#import <Foundation/Foundation.h>
#include <asl.h>
#include <mach/mach.h>
#ifndef myheader #define myheader
...后跟标头代码...#endif
关于预处理器似乎有很多困惑。
编译器看到一个#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语言也不允许这样做。
由于标头经常在一个以上的地方使用,include防护通常在C中使用。这看起来像这样:
#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
行仅在首次遇到时才被命名文件的内容替换。此后每次都将被忽略。
#include
为#import
s 后,编译和XCode智能感知响应能力得到了显着的性能改进。(我想我没有想象中的)
我同意杰森。
我被发现这样做了:
#import <sys/time.h> // to use gettimeofday() function
#import <time.h> // to use time() function
对于GNU gcc,它一直抱怨time()函数未定义。
因此,然后我将#import更改为#include,一切正常。
原因:
您#import <sys / time.h>:
<sys / time.h>通过使用#defines 仅包含<time.h> 的一部分。
您#import <time.h>:
不行。即使仅包含<time.h>的一部分,但
就#import而言,该文件现在已完全包含在内。
底线:
C / C ++传统上标头包括部件的其他包含文件。
因此,对于C / C ++标头,请使用#include。
对于objc / objc ++标头,请使用#import。
#include
就像C一样工作#include
。
#import
跟踪哪些头文件已被包含,如果在编译单元中多次导入头文件,则将其忽略。这样就不必使用标题防护。
最重要的一点是#import
在Objective-C中使用,不用担心标题是否多次导入了东西。
我知道这个线程很旧...但是在“现代时代” ..通过clang的@import
模块有一个非常优越的“包含策略” -通常被忽略。
通过将文本预处理器包含模型替换为更健壮,更有效的语义模型,模块改善了对软件库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 ...,因为模块本身是作为独立的模块编译的。此外,导入模块时,将自动提供使用该模块所需的任何链接器标志。此语义导入模型解决了预处理器包含模型的许多问题。
要启用模块,传递命令行标志-fmodules
又名CLANG_ENABLE_MODULES
中Xcode
-在编译时。如上所述,该策略消除了ANY和ALL LDFLAGS
。与之类似,您可以删除任何“ OTHER_LDFLAGS”设置以及任何“链接”阶段。
我发现编译/启动时间可以使您“感觉”更加敏捷(或者“链接”时可能会有更少的延迟?)..而且,它还提供了一个绝佳的机会来清除现在多余的Project-Prefix.pch文件,并且相应的构建设置GCC_INCREASE_PRECOMPILED_HEADER_SHARING
,GCC_PRECOMPILE_PREFIX_HEADER
以及GCC_PREFIX_HEADER
等
另外,尽管文档不足,您也可以module.map
为自己的框架创建,并以方便的方式将它们包括在内。 您可以查看我的ObjC-Clang-Modules github存储库,以获取有关如何实现此类奇迹的一些示例。
如果您熟悉C ++和宏,那么
#import "Class.h"
类似于
{
#pragma once
#include "class.h"
}
这意味着您的类仅在您的应用运行时才加载一次。
#pragma once
放在包含的文件中,而不是执行包含的文件中。-1。
如果在#.h文件中#include一个文件两次,则编译器将报错。但是,如果您多次导入文件,编译器将忽略该文件。
#include
同一文件两次不会导致错误。
#include
只是一种复制粘贴机制。故意使用#include
多个不包含包括“ X宏”在内的保护措施的情况。
#include
实现一种模板的C代码。他们做了a #define
,包括标头,#undef
d并重做了#define
,再次包含了相同的标头。由于定义的值不同,因此导致代码被参数化,有效并包含两次。因此,使用会有很多好处#include
,但是如果您使用的是C ++或ObjC之类的现代语言,则通常不需要。
#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
即使您#include
在代码中放置n次“ otherfile.h”,也不会在其中声明它。