一骤素、概述
在 Xcode 提供的構(gòu)建設置中匙睹,有一項稱為“MACH_O_TYPE ”愚屁,其作用是定義輸出的產(chǎn)品文件格式以及產(chǎn)品文件用于其他產(chǎn)品構(gòu)建時如何被鏈接。它的取值如下所示:
1痕檬、可執(zhí)行文件(mh_execute)(.app)
2霎槐、動態(tài)鏈接庫(mh_dylib)(.dylib)
3、包(mh_bundle)(.bundle)
4梦谜、靜態(tài)鏈接庫(staticlib)(.a)
5丘跌、可重定位的對象文件(mh_object)(.o)
作為iOS開發(fā)者,基本上只要關心可執(zhí)行文件唁桩、Bundle和靜態(tài)鏈接庫就可以了闭树。動態(tài)鏈接庫沒法用,而靜態(tài)庫(archieve)是.o的文件包荒澡,所以靜態(tài)庫完全可以替代.o文件报辱。
出于某些目的,比如設計架構(gòu)上將功能與展現(xiàn)相分離仰猖,或者重要功能與邊緣功能相分離捏肢,或者只是為了模塊功能劃分的清晰性等等,軟件在設計時可能會分成幾個工程來做饥侵。而對于iOS程序來說鸵赫,最終提供給移動端用戶的產(chǎn)品只能是ipa,即一個可執(zhí)行程序躏升,而其他工程所能提供的只能為其服務辩棒。這時程序員所能選擇的只有bundle或者靜態(tài)庫。本文將就靜態(tài)庫的一些使用經(jīng)驗膨疏、技巧做出敘述一睁,對于bundle的使用,將在另外的文章里進行敘述佃却。
最后稍微科普一下動態(tài)鏈接庫和靜態(tài)鏈接庫:
靜態(tài)鏈接是在編譯時進行的者吁,靜態(tài)鏈接庫(.a文件)實際上就是編譯好的程序代碼,如果有兩個程序都用到了同一個庫的話饲帅,且同時運行這兩個程序复凳,那么內(nèi)存中會有兩份相同的庫的代碼。動態(tài)鏈接是在運行時進行的灶泵,由操作系統(tǒng)管理育八,如果兩程序都用同一個DLL的話,實際上內(nèi)存中只有一份代碼赦邻。由于iOS開發(fā)嚴格的權限管理髓棋,即基本只限于沙盒內(nèi),所以動態(tài)鏈接庫這種東西是不準使用的。
二按声、基本流程
最簡單的流程:
在新建工程中選擇“Cocoa Touch Static Library ”膳犹,輸入工程名稱,一個靜態(tài)庫工程就完成了儒喊。新建幾個想要使用的類镣奋,編譯,生成最終的.a文件怀愧。將類的聲明頭文件與.a文件提供給主工程侨颈,將.a添加到主工程的target中的鏈接步驟中即可進行使用。
對于具體的使用步驟芯义,網(wǎng)上有很多哈垢,這里就不進行贅述了。
三扛拨、細節(jié)
1耘分、隱藏復雜性
庫的存在最基本意義在于,提供與主工程分離的功能模塊且不會暴露細節(jié)绑警。只暴露出想讓別人看到的內(nèi)容是模塊設計時需要詳細考慮的求泰。如果靜態(tài)庫的功能是提供一些API,那么很好的一種實踐是使用外觀模式计盒,提供一個簡單統(tǒng)一的對外類給主程序使用渴频。對外類使用單例也是一種常用的模式。使用外觀可以極大的降低子系統(tǒng)與主程序之間的耦合北启,隱藏子系統(tǒng)的復雜性卜朗。簡單地說,就是提供給主程序的產(chǎn)品只有一個頭文件和一個.a文件咕村,頭文件中只有一個類的聲明场钉,且這個類可以是一個單例。
2懈涛、前綴的使用
當開發(fā)靜態(tài)庫時逛万,需要注意前綴的使用。需要在設計時對類名附加前綴批钠,否則在主程序使用時可能會發(fā)生重名的風險宇植。如果主程序和子系統(tǒng)是同一個項目組還好,如果是由第三方价匠,且有多個子系統(tǒng)提供.a時,這種重名的幾率還是很大的呛每。
3踩窖、多個有依賴的靜態(tài)庫的使用
由于靜態(tài)鏈接庫是沒有鏈接這一步驟的,提供.a的作用和直接提供.a當中所包含的.o的作用是完全一樣的晨横。因而在編寫靜態(tài)庫工程時洋腮,可以只根據(jù)一個頭文件就可以調(diào)用一些方法箫柳,只要在程序真正運行時提供需要的.a就可以了(主程序中鏈接的順序可能要注意一下)。例如一個頭文件提供一個A類啥供,它包含a方法悯恍,但是只有聲明而沒有實現(xiàn)。在靜態(tài)庫工程中伙狐,可以實例化A類并且調(diào)用a方法涮毫,而不會發(fā)生任何錯誤。這種能力可以應用在一些的開發(fā)流程中贷屎。(當然也可以提供.a一起編譯罢防,最后提供一個大號的.a給主程序)
例如,軟件設計為如下所示:
其中唉侄,功能子系統(tǒng)的提供形式是.a咒吐,通用功能的提供形式也是.a。功能子系統(tǒng)提供各自的功能給主程序使用属划,且它們都要使用一些由通用功能模塊提供的方法恬叹。這時,通用功能的.a可以不提供給各個子系統(tǒng)同眯,只要將.h功能子系統(tǒng)就可以了绽昼。最后將功能子系統(tǒng)的3個.a和通用功能的.a一起提供給主程序就可以了。這樣做的好處是最終提供的庫的總體積會比較小嗽测,而且通用功能在開發(fā)過程中不必實時的將產(chǎn)品提供給各個子系統(tǒng)绪励,只要提供給主程序就可以了。只要提供的接口不變唠粥,通用功能模塊就不必為各子系統(tǒng)提供更新疏魏。
當然這是一種比較極端的情況,畢竟大多數(shù)模塊都要程序員自己進行測試晤愧,這時就必須提供通用功能的.a了大莫。
4、使用類別(Category)的靜態(tài)庫
類別模式用于向現(xiàn)有的類中添加方法官份,可用于解決類簇子類化太過復雜的問題只厘。Objective-C中直接支持此模式并廣泛應用。在實際應用當中舅巷,類別經(jīng)常作為組織類實現(xiàn)的工具羔味。例如NSObject就分為了幾十個類別。這種將一個巨大的類按不同功能分解到不同類別中的方式钠右,或者對同一個類在不同模塊進行擴展的方式赋元,同樣可以在靜態(tài)庫中使用。即,只要提供一個要擴展的類的頭文件搁凸,就可以對其使用類別進行擴展媚值。這種方式的應用沒有什么難理解的,只要注意編寫類別方法的時候需要添加前綴护糖,否則可能造成功能的替換混亂褥芒。
靜態(tài)庫中使用類別有一個bug要注意。在OTHER_LDFLAGS中使用 -ObjC 使靜態(tài)庫可以使用objective-c中的特性嫡良,比如KVC或者類別锰扶。但是對于只包含類別而不包含類的靜態(tài)庫,鏈接時有一個bug會阻礙靜態(tài)庫內(nèi)的.o的載入皆刺。使用 -all_load 或者 -force_load 來解決這個問題少辣。也就是說,大多數(shù)情況下都要使用 -ObjC 這個標識羡蛾,只有在靜態(tài)庫中只包含類別時才需要使用 -all_load (但實際上有時即使有類的時候也有載入不全的情況)漓帅。