彻底搞懂import "" 和 import <>

7,504 阅读5分钟

今天打开Xcode看到import的时候,突然想起来好像除了在刚出来工作面试iOS的时候背过它们的区别外,后来就再也没有深入了解过这两个究竟是什么作用,以致于到现在连作用区别都一时间说不上来,实在惭愧。今天还是来彻底研究一番。

一般情况下

我们新建一个项目,再创建一个类文件比如叫FooView,此时我们要在其它地方用到FooView的时候,我们一般这样

#import "FooView"

当我使用cocoapod安装第三方库,比如安装了Masonry,那么在用到Masonry的时候,一般我都会

#import <Masonry.h>

为什么不用 "",因为我发现用""编译器并不会给出提示,所以我一直以为只能用<>,但是在我做过的几个项目中,我其实并没有用到 <>,而是一直都用的 "",曾经也很奇怪为什么会不一样,但之前也只是想想,可能是项目设置里面加了什么东西,也没有仔细深入了解。(PS:这种精神还是不可取的)

所以就会有这样一个思维:正常情况下,自己新建的文件用"",而通过cocoapod安装或者引用系统库文件,用<>

在Stack Overflow上有一个回答较高的解释:

the quoted form is for “local” includes of files (you need to specify the relative path from the current file, e.g. #include “headers/my_header.h”), while the angle-bracket form is for “global” includes — those found somewhere on the include path passed to the compiler。
大概意思就是双引号用于引用本地文件,需要指定相对路径,尖括号用于全局引用,路径由编译器提供。

所以当我们用<>引用我们新建的文件的时候,就会有这样一个提示:

'FooView.h' file not found with <angled> include; use "quotes" instead

user header map

Enable the use of Header Maps, which provide the compiler with a mapping from textual header names to their locations, bypassing the normal compiler header search path mechanisms. This allows source code to include headers from various locations in the file system without needing to update the header search path build settings。

在Xcode项目 - Build Settings 下搜索:search path

[image:78A149E8-4306-4DA5-81D3-CCD63846E5A3-82034-0000F225FE8D3778/截屏2020-03-05下午1.37.38.png]

我们会看到有一个Use Header Maps开关,默认是打开的。这个意思是:开启这个开关后,在本地会根据当前目录生成一份文件名和相对路径的映射,依靠这个映射,我们可以直接import工程里的文件,不需要依靠header search path。 我们在管理项目的时候,一般都会把文件放在各个模块下面,模块以各个文件夹区分,在Xcode中创建文件夹会有两种方式,一种是虚拟文件夹(文件还是在项目根目录下),一种是真实文件夹。我之前一直觉得他们就是文件在不在一起的区别,当我关掉Use Header Maps这个选项的时候,这两种文件夹在这里又表现出了不一致。

我一开始是用New Group With Folder创建的真实文件夹 [image:2F4C37EF-E8AB-482E-AD2A-87C428D3C1A2-82034-0000F2A0C5020E0D/截屏2020-03-05下午1.46.27.png]

EventViewController是BaseViewController的子类,在头文件中引用了BaseViewController。 当我关掉Use Headers Maps选项的时候,就会报以下错误: [image:4FC4F5A1-9470-4A69-85BC-BA5C0112EC2C-82034-0000F2B585438D7E/截屏2020-03-05下午1.47.57.png]
相对路径找不到BaseViewController,这时候EventViewController是在Event文件夹下,BaseViewController是在Base文件夹下,由于关闭了Header Maps,所以无法直接引用。

但是当我用虚拟文件夹管理文件的时候,由于他们都是在根目录下,所以通过相对路径引用是完全没有问题的,即使关闭了Use Headers Maps选项。

该如何解决?

这时候我们就涉及到Header Search PathsUser Header Search Paths。两者都是提供search path,区别在于一个指明是用户的。并且如果编译器不支持user headers概念,会从header search paths中去寻找。并且看上面有一个Always Search User Paths,但是已经被Deprecated。查阅资料知道

如果开启,<> 和 “” 都可以引用,关闭的话,user headers 只能通过””引用。

我们现在要让编译器知道这个文件在哪里,所以要在search paths里面添加引用文件所在的文件夹。 [image:B60806DF-2933-40DB-84F6-C8A9957E7B67-82034-0000F47B21B01244/截屏2020-03-05下午2.20.22.png]

在Header Search Paths里添加的话,无论import “” 还是 import <>都是没有问题的,在User Header Search Paths里添加,只能使用import “”

解答上面cocopad安装第三方库引用的疑问

看下面的三种方式

#import "Masonry.h"
#import <Masonry.h>
#import "Masonry/Masonry.h"

思考一下这三种方式是否都正确? . . . 答案是:都正确。

之前一直困惑用哪种方式,又好像哪种方式都正确。这次直接看 search paths下面,发现 [image:155A198A-E734-4AFE-9B28-E023AB236215-82034-0000F79AD1B66DD4/截屏2020-03-05下午3.17.05.png]

cocopod在install的时候,会将第三方库的framework路径添加到Header Search Paths下,所以我们可以直接import,也可以import它的模块下的文件

总结

如果按照Xcode默认配置的话,自己新建的文件直接import “”使用,cocoapod安装的第三方库使用import “”、import <>都可以使用。如果关闭Use Header Maps,文件不在根目录下的话,需要手动添加路径到search paths中,添加到User Header Search Paths只能通过import ”“使用,添加到Header Search Paths两种方式都可以。

参考:关于Objective-C中的import - 掘金