Xcode構(gòu)建過程的后臺工作(一)構(gòu)建過程
Xcode構(gòu)建過程的后臺工作(二)clang構(gòu)建
Xcode構(gòu)建過程的后臺工作(四)鏈接
構(gòu)建過程:Swift構(gòu)建
我們現(xiàn)在將深入研究Swift和構(gòu)建系統(tǒng)如何協(xié)同工作以在項(xiàng)目中查找聲明。Clang單獨(dú)編譯了每個Objective-C文件诺擅。這意味著如果要在另一個文件夾中 查找一個類系吭,則必須導(dǎo)入聲明該類的頭文件谬擦。但Swift的設(shè)計不需要寫入頭文件房官。這使初學(xué)者更容易上手該語言趾徽。 并避免了在不同文件中重復(fù)一個聲明。但這意味著編譯器必須執(zhí)行一些額外的記錄工作翰守。下面講講記錄工作如何運(yùn)作孵奶。讓我們回到示例PetWall應(yīng)用程序。
該應(yīng)用程序在ViewCcontroller中 有一個Swift界面蜡峰。Objective-C app代理了袁,和Swift單元測試。 為了編譯哪怕只是上面這個PetViewController部分湿颅,編譯器也要執(zhí)行四種不同的運(yùn)算载绿。首先,它必須找到聲明油航,既可以在Swift目標(biāo)內(nèi)崭庸,也可以來自O(shè)bjective-C。此外劝堪,它還要生成描述文件內(nèi)容的 接口冀自。這樣它的聲明就可以被Objective-C和其他Swift目標(biāo)中找到并使用。 在接下來的部分中秒啦,我將通過這個例子來分別闡述這四個任務(wù)熬粗。首先是在Swift目標(biāo)中查找聲明。編譯PetViewController.swift時余境,編譯器會查找 PetView初始程序類型驻呐,以便檢查調(diào)用。但在此之前芳来,它要解析PetView.swift并驗(yàn)證它含末,以確保初始程序的聲明是正常的。
編譯器很聰明 即舌,它知道它不需要檢查初始程序的主體佣盒。但它仍然需要做一些工作去處理文件的接口部分。這與Clang不同顽聂,編譯一個Swift文件時肥惭,編譯器將解析目標(biāo)中的所有其他Swift文件,以檢查與接口相關(guān)的部分紊搪。
在Xcode 9中蜜葱,這導(dǎo)致了在增量調(diào)試構(gòu)建中的一些重復(fù)工作。因?yàn)榫幾g器單獨(dú)編譯每個文件耀石。文件能夠并行編譯牵囤,但它強(qiáng)制編譯器重復(fù)解析每個文件。解析一次作為實(shí)現(xiàn)文件產(chǎn)生一個.o,解析多次是作為接口來查找聲明揭鳞。
Xcode 10減少了這種開銷炕贵。它通過將文件合并成組,在依舊最大化并行的同時汹桦,盡可能多地共享工作來實(shí)現(xiàn)鲁驶。
在組中重復(fù)利用解析,只在跨組處理時重復(fù)舞骆。由于組的數(shù)量通常相對較低,因此 可以顯著加快增量調(diào)試構(gòu)建径荔。
從Objective-C中查找聲明
Swift代碼不僅調(diào)用其他Swift代碼督禽。 它也可以調(diào)用Objective-C∽艽Γ回到我們的PetWall示例應(yīng)用程序狈惫,我們可以看到,這是至關(guān)重要的鹦马,因?yàn)閁IKit等系統(tǒng)框架是用Objective-C編寫的胧谈。Swift與其他語言不同,它不需要外部功能 接口荸频。例如菱肖,您必須編寫Swift聲明給每個Objective-C API。但是旭从,編譯器內(nèi)置了Clang的一大部分稳强,并將其用作庫。這樣就可以直接導(dǎo)入Objective-C框架和悦。
那么Objective-C聲明來自哪里退疫?導(dǎo)入器會根據(jù)目標(biāo)的類型查找頭文件。任何目標(biāo)在導(dǎo)入Objective-C框架時鸽素,導(dǎo)入器在頭文件中查找聲明褒繁,以顯示該框架的 Clang模塊映射。在Swift和Objective-C代碼混編的框架內(nèi)馍忽,導(dǎo)入器在umbrella頭文件中查找聲明棒坏。這個頭文件定義了公共接口。這樣舵匾,框架內(nèi)的Swift代碼可以調(diào)用同一框架中公共Objective-C代碼俊抵。最后,在您的應(yīng)用和 單元測試中坐梯,可以導(dǎo)入目標(biāo)的橋接頭文件徽诲,允許其中的聲明被Swift調(diào)用。
當(dāng)導(dǎo)入器找到聲明時,通常會修改它們谎替,讓它們更口語化偷溺。比如它會導(dǎo)入Objective-C方法,用NSError慣用語作為使用Swift的內(nèi)置錯誤處理語言功能的throwing方法钱贯。特別是它會刪除動詞和介詞后面的參數(shù)類型名稱挫掏。 例如,drawPet:atPoint方法有單詞pet秩命,和跟在一個動詞draw后的pet類型的參數(shù)尉共。
同樣的單詞point,代表參數(shù)類型CGPoint弃锐,后跟介詞at袄友。
Swift中省略了這些單詞,只導(dǎo)入函數(shù)draw at霹菊。怎么做到的剧蚣?編譯器包含常用英語動詞和介詞列表。 因?yàn)樗皇且粋€硬編碼列表而且人類語言很復(fù)雜旋廷,有時候它會缺詞鸠按。
此外,為了匹配Swift的命名約定饶碘,導(dǎo)入器會重命名方法目尖,根據(jù)詞性刪除單詞。 例如熊镣,動詞Feed不在列表中卑雁,因此feedPet不會像我們預(yù)期的那樣作為Feed導(dǎo)入。發(fā)生這種情況時绪囱,您可以使用 NS_Swift_Name注解讓編譯器導(dǎo)入你要的方法形式测蹲。
如果您想查看如何將Objective-C標(biāo)頭 導(dǎo)入Swift,您可以到Xcode的相關(guān) 項(xiàng)目彈出窗口鬼吵。
它在源編輯器的左上角扣甲。選擇生成的接口,就能看到接口在不同版本的Swift中的樣子齿椅。這就是Swift如何導(dǎo)入Objective-C琉挖。
生成在Objective-C中使用的接口
Objective-C中如何導(dǎo)入Swift?答案是Swift會生成一個頭文件涣脚,可以進(jìn)行導(dǎo)入示辈。這允許您在Swift中編寫類并從Objective-C中調(diào)用它們。讓我們看看它是如何工作的遣蚀。編譯器將為擴(kuò)展NSObject的Swift類和@obc標(biāo)記的方法生成 Objective-C聲明矾麻。
對于單元測試的app纱耻,頭文件會包括公共聲明和內(nèi)部聲明。這樣就能在app的Objective-C部分使用內(nèi)部Swift险耀。但是弄喘,對于框架,生成的頭文件只包含公共聲明甩牺,因?yàn)樗跇?gòu)建產(chǎn)品中蘑志,是框架的公共接口的一部分。
在上圖右側(cè)贬派,您看到編譯器將Objective-C類鏈接到名字變形的Swift類急但,該名稱包含模塊名稱PetWall。當(dāng)兩個模塊定義了有相同名稱的類時搞乏,這可以防止運(yùn)行時發(fā)生沖突羊始。 您可以通過將標(biāo)識符傳遞給obc屬性讓Swift重命名Objective-C類。但是如果你這樣做查描,你要確保名稱不沖突。在這里柏卤,我使用了PWL前綴冬三,以減少沖突的可能性。這樣就可以在Objective-C中引用這個類PWLPetCollar 缘缚。
編譯器采用類似的方法生成其他Swift目標(biāo)的接口勾笆。為此,Swift基于Clang的模塊概念進(jìn)行構(gòu)建桥滨,并且更深層的融入語言窝爪。在Swift中,模塊是可分布的聲明單元齐媒。為了能夠使用這些聲明蒲每,您必須導(dǎo)入模塊。您可以導(dǎo)入Objective-C模塊例如XEtest喻括。在Xcode中邀杏,每個Swift目標(biāo)都會生成一個單獨(dú)的模塊,包括您的app target唬血。所以要導(dǎo)入app的主模塊望蜡,以便進(jìn)行單元測試。
導(dǎo)入模塊時拷恨, 編譯器會反序列化一個特殊的Swift模塊文件脖律,在使用它時檢查類型。 例如在此單元測試中腕侄,編譯器將從PetWall Swift模塊加載PetViewController小泉,以確保正確創(chuàng)建控制器芦疏。這類似于編譯器在目標(biāo)中查找聲明的方式。
除此之外編譯器加載一個匯總模塊的文件膏孟,而不是直接解析Swift 文件眯分。
編譯器生成此Swift模塊文件很多就像Objective-C頭文件。但它不是文本柒桑,而是二進(jìn)制表示弊决。 它包括內(nèi)聯(lián)函數(shù)的主體,就像Objective-C中的靜態(tài)內(nèi)聯(lián)函數(shù)或C++中的頭文件實(shí)現(xiàn)一樣魁淳。但是飘诗,有一點(diǎn)需要注意的就是它包含了私有聲明 的名稱和類型。這讓您能在調(diào)試器中引用它們界逛,很方便昆稿,但也意味著,您不能用私人秘密來命名私有變量息拜。
對于累加構(gòu)建溉潭, 編譯器會生成部分Swift模塊文件,然后將它們合并到一個表示整個模塊內(nèi)容的文件中少欺。這種合并過程還可以生成單個Objective-C頭文件喳瓣。
在許多方面,這類似于鏈接器將目標(biāo)文件整合成單個可執(zhí)行文件時所執(zhí)行的操作赞别。 下文將主要講述連接器畏陕。