一:从include开始
首先看看include做了什么,新建一个app项目,语言选择OC,然后把main.m里的代码注了;
新建一个A.h和A.c
A.h不用引入任何头文件,定义一个变量a, 一个结构体mach_header,两个宏定义
//A.h
struct mach_header {
int magic;
};
#define MH_MAGIC 114
#define MH_CIGAM 514
A.c用include引入A.h ,然后添加一个main函数
//A.c
#include "A.h"
int main(){
return MH_MAGIC + MH_CIGAM;
}
接下来用clang -E看看预编译做了什么
clang -E A.c
输出
# 1 "A.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 400 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "A.c" 2
# 1 "./A.h" 1
struct mach_header {
int magic;
};
# 9 "A.c" 2
int main(){
return 114 + 514;
}
可以看到,除去#注释,做了两件事:
1.把.h的东西copy进来
2.替换了宏定义
这种copy非常无脑,重复的引用就会重复的copy,可以试一下看看会发生什么;
分别创建BCD的.h和.c文件,.h里内容全部注释
然后在B.h和C.h里#include "A.h";
在D.h里#include "B.h",#include "C.h"
//A.h
struct mach_header {
int magic;
};
#define MH_MAGIC 114
#define MH_CIGAM 514
//B.h
#include "A.h"
//C.h
#include "A.h"
//D.h
#include "C.h"
#include "B.h"
然后编译,可以看到A.h中报错,Redefinition of 'mach_header',
重复定义的mach_header. copy两遍当然会重复定义.
import也是做的和include一样的事,但是它可以防止重复的引入,就是通过这样一种结构来实现的
#ifndef A_h
#define A_h
//h的具体内容
#endif
这是一种编译器约定用法,A_h是一个标记,ifndef表示如果没有这个标记,那么就define定义这个标记,标记是唯一的,一般命名为"文件名_h"
实际上现在Xcode创建C文件已经自带这个了,刚才都特意注释的,也就是说include加上这个结构就可以防止重复的引用
而用import可以直接实现这个效果,并且没有显式的#ifndef.
所以现在下面这两种情况都可以编译成功
1.给A.h加ifndef
#ifndef A_h
#define A_h
struct mach_header {
int magic;
};
#define MH_MAGIC 114
#define MH_CIGAM 514
#endif /* A_h */
2.把include都换成import,同时A.h也不必加ifndef了
//B.h
#import "A.h"
//C.h
#import "A.h"
//D.h
#import "B.h"
#import "C.h"
二:import "" 和import <>
先增加一个文件夹,创建一个E.m和E.h

既然include和import是拷贝内容,那么编译器就得找到这个文件.
build setting -> search paths中有一个 use header maps,默认是开启的,先把它关了
然后在A.c添加
#import "E.h"
编译,报错 'E.h' file not found
改成
#import "RealFolder/E.h"
这样就不报错了,因为引入头文件本来是需要相对路径的.
而use header maps所做的,就是生成一份"头文件"->"相对路径"的隐射文件,项目中创建的所以的头文件都会添加进去,
当import时,编译器通过隐射去找路径.
当关闭use header maps时,引入头文件就需要补充相对路径;
不写相对路径也行,Xcode还有其他方案search方案,那就是Header search paths和user header search paths

首先两者添加的方式是一样的,添加一个路径,比如$(PROJECT_DIR)/CommonProject_OC/RealFolder,可以添加多条.
其次这两者的区别很小,对于用户添加的头文件,包括库,对于其路径:
添加在Header search paths的,import "" 和import <>都可以引入;
添加在user header search paths的,只能import "" 引入
另外还有一个废弃的always search user paths,如果设置true,也是一样import "" 和import <>都可以引入
现在在user header search paths中添加$(PROJECT_DIR)/CommonProject_OC/RealFolder
现在引入#import "E.h"就可以编译成功了.
换成会#import <E.h> 会报错 'E.h' file not found with <angled> include; use "quotes" instead
use header maps不会作用于Framework search paths和library search paths,这俩要分别设置,一般add进来就会自动设置.
cocoapods (use Framework)会在header search path和framework search path都添加

所以这三种都可以
#import "AFNetworking.h"
#import <AFNetworking.h>
#import <AFNetworking/AFNetworking.h>
二.hmap文件
打开use header maps,编译,查看编译记录,搜索hmap

然后打开路径

每个target都会生成一个.build文件夹,因此cocoapods会更多.每个.bulid里有6个.hmap文件
这个hmap文件就是前面说到的隐射表,是一个二进制文件,用来提高头文件的查找速度,是这样一种结构.
HeaderMapTypes.h

hmap由HMapHeader, HMapBucket和头文件的内容字符串组成
HMapHeader是一些描述信息,包含几个HMapBucket
HMapBucket由key,prefix和suffix组成,key是头文件的名称,可能是ViewController.h或者AFNetworking/AFSecurityPolicy.h,
prefix是文件夹路径,suffix是文件名.pre-suff就是文件路径.
几个头文件对应几个bucket,通过在偏移对应到文件具体的位置,和mach-o类似.
可以用brew安装hmap工具来查看:
brew install milend/taps/hmap
查看内容
hmap print .../xxx.hmap
输出
A.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/A.h
AppDelegate.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/AppDelegate.h
B.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/B.h
C.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/C.h
D.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/D.h
E.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/RealFolder/E.h
FirstObjc.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/FirstObjc.h
SceneDelegate.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/SceneDelegate.h
SecondObjc.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/SecondObjc.h
ViewController.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/ViewController.h
网友评论