一、搜索路徑設(shè)置

$(SRCROOT)宏和$(PROJECT_DIR)宏都指xxx.xcodeproj所在的目錄
$(default) 代替 /Users/xxx/Library/Developer/Xcode/DerivedData/xxxxx-erpfssifaoxedbccegoqjiclrfds ,這個(gè)路徑受 xcode->Preferences->locations 影響。本文只討論默認(rèn)情況這種。
$(SYMROOT) = $(default)/Build
$(BUILD_ROOT) 、$(BUILD_DIR) = $(SYMROOT)/products = $(default)/Build/products
$(CONFIGURATION) 當(dāng)前的Build configuration,Debug時(shí)值為Debug。
$(EFFECTIVE_PLATFORM_NAME) 當(dāng)前平臺(tái)的名字,模似器時(shí)為值為-iphonesimulator ,當(dāng)為真機(jī)時(shí)為-iphoneos
$(CONFIGURATION_BUILD_DIR) = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) = $(default)/Build/products/Debug-iphoneos (Build configuration為debug,平臺(tái)為真機(jī)情況)
在編譯時(shí),編譯器會(huì)將相對(duì)路徑替換成絕對(duì)路徑,因此,頭文件絕對(duì)路徑=搜索路徑+相對(duì)路徑。
Framework Search Paths:框架文件搜索路徑設(shè)置(.framework文件)
Header Search Paths:頭文件搜索路徑設(shè)置(.h文件)
Library Search Paths:庫(kù)搜索路徑設(shè)置(靜態(tài)庫(kù).a文件)
Header Search Paths
設(shè)置系統(tǒng)目錄空間頭文件(.h文件)搜索路徑。
例如:引用工程中,路徑為:xxx/testDemo/scr/test.h 的頭文件,目錄結(jié)構(gòu)如下:

如果在Header Search Paths中添加$(SRCROOT),則引用頭文件時(shí),需要寫為#include "scr/test.h"
如果在Header Search Paths中添加$(SRCROOT)/scr,那么頭文件引用直接引用 #include "test.h"
System Header Search Paths
和Header Search Paths基本一樣,區(qū)別只在于Header Search Paths以一種抑制系統(tǒng)搜索路徑中找到的標(biāo)頭的大多數(shù)警告的方式傳遞給編譯器。
This setting is very similar to "Header Search Paths", except that headers are passed to the compiler in a way that suppresses most warnings for headers found in system search paths.
所以通常使用Header Search Paths來(lái)設(shè)置,下文也忽略這個(gè)設(shè)置。
User Header Search Paths
設(shè)置用戶目錄空間頭文件(.h文件)搜索路徑。
和Header Search Paths的區(qū)別如下:
當(dāng)import時(shí), 有兩種方式:
#import <SomeClass.h>
#import "SomeClass.h"
在Header Search Paths中設(shè)置SomeClass的路徑
我們知道,在C語(yǔ)言中,使用尖括號(hào)引用,預(yù)處理器會(huì)從系統(tǒng)目錄空間(對(duì)應(yīng)Header Search Paths)中搜索文件,所以此時(shí)可以正確引用到。同樣,使用雙引號(hào)引用,預(yù)處理器會(huì)先從用戶目錄空間(對(duì)應(yīng) User Header Search Paths)搜索,如果沒有找到,再?gòu)南到y(tǒng)目錄空間(對(duì)應(yīng)Header Search Paths)中搜索文件,所以也可以正確正確引用到。在User Header Search Paths中設(shè)置SomeClass的路徑
使用尖括號(hào)引用就會(huì)報(bào)錯(cuò),因?yàn)檎也坏綄?duì)應(yīng)的頭文件。使用雙引號(hào)則可以正常引用。原理同上。
所以,當(dāng)需要設(shè)置頭文件引用路徑的時(shí)候,不推薦設(shè)置這里,推薦設(shè)置Header Search Paths。
Always Search User Paths
設(shè)置是否總是搜索用戶目錄空間,如果設(shè)置為YES,則上文中的例子,在User Header Search Paths中設(shè)置SomeClass的路徑,也可以使用#import <SomeClass.h>這種方式引用。這個(gè)設(shè)置已被棄用,不推薦設(shè)置。
Framework Search Paths
設(shè)置框架文件(.framework文件)搜索路徑
需要在Framework Search Paths中添加對(duì)應(yīng)framework所在目錄的路徑,引用時(shí),需要寫為#include <aaa/aaa.h>
這里需要注意,設(shè)置了Framework Search Paths,僅僅是在編譯的時(shí)候可以找到對(duì)應(yīng)的頭文件,具體是否將framework鏈接進(jìn)當(dāng)前target,還需要看是否設(shè)置Link Binary With Library 或 對(duì)應(yīng)的Other Linker Flags
Library Search Paths
設(shè)置靜態(tài)庫(kù)(.a文件)搜索路徑
這里需要注意,設(shè)置了Library Search Paths,就會(huì)導(dǎo)致當(dāng)前靜態(tài)庫(kù)被鏈接進(jìn)當(dāng)前target
二、模塊化導(dǎo)入(語(yǔ)義導(dǎo)入)
也就是所謂的@import aaa; 模塊化導(dǎo)入具體有什么優(yōu)缺點(diǎn),網(wǎng)上一堆資料,同學(xué)們可以自行百度,這里引用了一段stackoverflow上的回答
It's a new feature called Modules or "semantic import". There's more info in the WWDC 2013 videos for Session 205 and 404. It's kind of a better implementation of the pre-compiled headers. You can use modules with any of the system frameworks in iOS 7 and Mavericks. Modules are a packaging together of the framework executable and its headers and are touted as being safer and more efficient than
#import.
One of the big advantages of using@importis that you don't need to add the framework in the project settings, it's done automatically. That means that you can skip the step where you click the plus button and search for the framework (golden toolbox), then move it to the "Frameworks" group. It will save many developers from the cryptic "Linker error" messages.
You don't actually need to use the@importkeyword. If you opt-in to using modules, all#importand#includedirectives are mapped to use@importautomatically. That means that you don't have to change your source code (or the source code of libraries that you download from elsewhere). Supposedly using modules improves the build performance too, especially if you haven't been using PCHs well or if your project has many small source files.
Modules are pre-built for most Apple frameworks (UIKit, MapKit, GameKit, etc). You can use them with frameworks you create yourself: they are created automatically if you create a Swift framework in Xcode, and you can manually create a ".modulemap" file yourself for any Apple or 3rd-party library.
這里主要說下,怎么設(shè)置自己的庫(kù)可以被語(yǔ)義導(dǎo)入。
在XCode的build setting內(nèi),Packaging內(nèi)有以下設(shè)置module map的選項(xiàng)
Defines Module (DEFINES_MODULE) :
如果設(shè)置為YES,會(huì)認(rèn)為項(xiàng)目自定義自己的組件,允許項(xiàng)目通過組件的方式引入Module Map File (MODULEMAP_FILE)
用來(lái)管理LLVM的module map,定義編譯器組件結(jié)構(gòu).如果defines module為YES的時(shí)候,如果Module Map File沒填,會(huì)自動(dòng)生成.
在Cocoapod中,我們可以在podfile內(nèi)添加use_modular_headers!允許所有pod語(yǔ)義導(dǎo)入.也可以通過:modular_headers => true配置特定的pod.

三、頭文件引用方式總結(jié)
iOS中頭文件,有5種引用方式
#import "aaa.h"#import "aaa/aaa.h"#import <aaa.h>#import <aaa/aaa.h>@import aaa;
#import "aaa.h"
這種引用方式,可以引用到的頭文件,有3種。
-
Header Search Paths中對(duì)應(yīng)目錄的文件。 -
User Header Search Paths中對(duì)應(yīng)目錄的文件。 - 當(dāng)前project中包含的頭文件,也即
project.pbxproj文件中包含的頭文件。
#import "aaa/aaa.h"
這種引用方式,可以引用到的頭文件,只有2種。
-
Header Search Paths中對(duì)應(yīng)目錄的文件。 -
User Header Search Paths中對(duì)應(yīng)目錄的文件。
#import <aaa.h>
這種引用方式,可以只可以引用到 Header Search Paths 中對(duì)應(yīng)目錄的文件。
#import <aaa/aaa.h>
這種引用方式,可以引用到的頭文件
-
Header Search Paths中對(duì)應(yīng)目錄的文件。 -
Framework Search Paths中,對(duì)應(yīng)framework的頭文件 - 上文中,通過語(yǔ)義導(dǎo)入的模塊,使用這種方式,Xcode可以自動(dòng)解析為語(yǔ)義導(dǎo)入,其他方式不行。
@import aaa;
這種引用方式,只可以引用到開啟了模塊導(dǎo)入的模塊,即Defines Module設(shè)置為YES的庫(kù),如果沒有開啟模塊導(dǎo)入,則會(huì)報(bào)錯(cuò)。
綜合上述5中情況,我們可以看出,#import <aaa/aaa.h>和#import "aaa.h"這兩種情況,是更優(yōu)的選擇。
結(jié)合Cocoapods來(lái)看,一般來(lái)說,當(dāng)我們使用Cocoapod的時(shí)候,Cocoapod會(huì)自動(dòng)給我們添加對(duì)應(yīng)的Header Search Path。

Cocoapod自動(dòng)生成的目錄結(jié)構(gòu)如下

所以當(dāng)我們使用#import <Masonry/Masonry.h>這種方式引用的時(shí)候,實(shí)際上我們用到的Header Search Paths是"${PODS_ROOT}/Headers/Public"這個(gè)路徑。同理,可以使用#import <Masonry.h>導(dǎo)入,使用用到的Header Search Paths是"${PODS_ROOT}/Headers/Public/Masonry"路徑。
所以一般情況下,我們使用Cocoapod,上述5中引用方式,除了語(yǔ)義導(dǎo)入,都可以正常使用。
Cocoapod支持非常多種設(shè)置,例如:
- 當(dāng)我們
:generate_multiple_pod_projects=>true設(shè)置,開啟多project結(jié)構(gòu),此時(shí)每個(gè)Pod都是自己?jiǎn)为?dú)的project,也就是說不是在同一個(gè)Pod.project中。#import "aaa.h"沒法通過同project索引頭文件,和#import <aaa/aaa.h>一樣,可以通過Header Search Path索引頭文件。 - 當(dāng)我們使用
use_frameworks!,此時(shí)Cocoapod不會(huì)設(shè)置Header Search Path,而是會(huì)設(shè)置Framework Search Path,此時(shí)可以使用#import <aaa/aaa.h>正常引用。如果沒有使用多project結(jié)構(gòu),那么Pod.project目錄下的各個(gè)Pod庫(kù),還可以使用#import "aaa.h"互相引用,因?yàn)樗麄兌际且粋€(gè)project下的。但是主工程和Pod工程不是一個(gè)工程下的,所以主工程中引用Pod庫(kù)文件,不可以使用#import "aaa.h"。同理,如果結(jié)合多project結(jié)構(gòu),不同Pod庫(kù)之間,也不可以使用#import "aaa.h"引用,因?yàn)榇藭r(shí)不再在同一個(gè)project下。 - 當(dāng)我們使用
use_modular_headers!,此時(shí)Cocoapod設(shè)置Header Search Path,此時(shí)#import <aaa/aaa.h>和#import "aaa.h"都可以通過Header Search Path索引頭文件。但是如果使用#import <aaa/aaa.h>,會(huì)被Xcode自動(dòng)替換為語(yǔ)義導(dǎo)入,即@import aaa;。具有更優(yōu)的性能,所以推薦使用#import <aaa/aaa.h>
綜上所述,當(dāng)我們使用Cocoapod的時(shí)候。
- 如果需要引用別的Pod庫(kù)中的頭文件,推薦使用
#import <aaa/aaa.h>。 - 當(dāng)Pod庫(kù)引用自己的頭文件的時(shí)候,推薦使用
#import "aaa.h"