目錄:
1. 庫是什么?
2. 靜態(tài)庫與動態(tài)庫的區(qū)別
3. 使用庫
4. iOS系統(tǒng)中的庫
庫是什么?
下面這張圖大家一定很熟悉,這是windows上經(jīng)常見到的一幕,我們可能剛剛安裝完一個軟件或者某個大型游戲,滿心歡喜的準備啟動時,蹦出這個東西:

這個就是庫引起問題,具體我們下面會進行分析。那么庫是什么?
本質上來說庫是一種可執(zhí)行代碼的二進制形式,可以被操作系統(tǒng)載入內存執(zhí)行。通俗地講,庫就是一個組件,一般是可以復用的組件,這樣每個需要這個組件的程序都可以使用這個組件,如果組件的代碼內聯(lián)在程序中,則失去組件的意義。
開發(fā)中為了實現(xiàn)快速迭代,我們通常要避免造輪子:首先自己造的輪子問題多,其次造輪子時間長。 所以我們通常會考慮開源庫。
開源庫是別人寫好的現(xiàn)有的,成熟的,可以復用的代碼,你可以使用但要記得遵守許可協(xié)議。使用開源庫首先必須了解代碼所遵循的協(xié)議,常見的協(xié)議如gpl bsd mit等,分清各種協(xié)議需要承擔的責任,例如我們使用的這份代碼的頭文件中描述了協(xié)議:

其他開源庫都相應github頁面上都會描述遵循的協(xié)議。
大家如果留意iOS系統(tǒng)中可以享用的開源庫,會發(fā)現(xiàn)作為一個iOS開發(fā)者的幸福:大量有用高質量的開源庫,并且使用相對寬松的多的協(xié)議,可以讓開發(fā)者使用的同時不用太關注侵權和付費問題,而大家如果使用大型的開源庫時,比如音視頻處理的ffmpeg,會發(fā)現(xiàn)這個庫使用了嚴苛的協(xié)議,開發(fā)者使用時就要關注是否修改源碼?修改后如果負責?使用了如何收費?是否侵權等諸多問題。
我想這也是iOS開發(fā)者為何這樣如泉涌一般出現(xiàn),因為這樣一個開放、相對自由又低門檻的環(huán)境讓許多新人有一個更快進入、更熟練進階的學習曲線。
協(xié)議參考:
http://blog.csdn.net/nightmare/article/details/12405109
http://www.cnblogs.com/Wayou/p/how_to_choose_a_license.html
靜態(tài)庫與動態(tài)庫的區(qū)別
庫按照鏈接的方式可以分為兩種,靜態(tài)庫和動態(tài)庫。
靜態(tài)庫
【靜態(tài)庫】是因為在鏈接階段,會將匯編生成的目標文件.o與引用到的庫一起鏈接打包到可執(zhí)行文件中。因此對應的鏈接方式稱為靜態(tài)鏈接。靜態(tài)庫的代碼在編譯鏈接后已經(jīng)被載入可執(zhí)行程序,因此體積較大。靜態(tài)庫的“靜態(tài)”是指編譯鏈接后庫已經(jīng)固定在可執(zhí)行文件中,如果需要更新庫中內容,需要重新編譯鏈接,才能在可執(zhí)行程序中生效,對程序的更新、部署和發(fā)布頁會帶來麻煩。
靜態(tài)庫可以看成是一堆對象.o文件(object files)的歸檔,所以靜態(tài)庫可以通過ar -x xxxx.a 來分解出其中的所有.o文件。當鏈接這樣一個庫到應用中時,static linker將會從庫中收集這些對象.o文件并把它們和應用的對象代碼一起打包到一個二進制文件中。這意味著應用的可執(zhí)行文件大小將會隨著庫的數(shù)目增加而增長。另外,當應用啟動時,應用的代碼(包含庫的代碼)將會一次性地導入到程序的地址空間中去。
參考下圖:

動態(tài)庫
【動態(tài)庫】在程序編譯時并不會被鏈接到目標代碼中,如下圖可見,可執(zhí)行文件中只是保存動態(tài)庫各個api的引用,保留著相對地址,在程序運行時,等可執(zhí)行程序中使用動態(tài)庫的某個api時,動態(tài)庫會載入到內存某個區(qū)域(非當前可執(zhí)行文件所在內存塊),可執(zhí)行程序所在進程將會生成這個動態(tài)庫的空間映射,從而被進程調用。
由此可見,動態(tài)庫是直到程序啟動時被需要時才加載到內存(增加了啟動時間,如果需要運行時再加載,需要處理),app啟動時,系統(tǒng)在內核態(tài)完成一些必要配置,從App的MachO文件解析出dyld的地址啟動dyld,然后通過dyld加載依賴的動態(tài)庫。 并且,不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例,規(guī)避了空間浪費問題(目前在iOS系統(tǒng)上不會這樣,因為iOS系統(tǒng)的沙盒機制禁用了進程之間的動態(tài)庫共享)。動態(tài)庫在程序啟動時才被載入,也解決了靜態(tài)庫對程序的更新、部署和發(fā)布頁會帶來麻煩。用戶只需要更新動態(tài)庫即可,可以實現(xiàn)增量更新。

iOS中的dylib支持上述形式,但其他動態(tài)庫不支持。
windows系統(tǒng)支持上圖形式:dll動態(tài)庫,
自己開發(fā)的程序可以加載系統(tǒng)的dll,這樣程序的大小變得很小。對于開篇windows上碰到的彈窗問題,其實問題就在動態(tài)庫的致命弱點上:由于一個系統(tǒng)中的不同軟件如果是基于同于dll的不同版本,不同版本dll之間的接口或內部邏輯又有所差異就會造成系統(tǒng)中某個軟件可以用,其他就不可以用,但同一時刻系統(tǒng)又只保留一個dll,所以無法保證這些軟件都能正常使用。
這也體現(xiàn)了windows和iOS兩個系統(tǒng)對動態(tài)庫的寬容性,前者對每個系統(tǒng)版本中dll的兼容性做的不好,并且允許用戶自己生成的dll文件,而后者兼容做的好的多,apple這方面為了避免出現(xiàn)這個情況,在iOS8之前是不允許用戶自定義的動態(tài)庫出現(xiàn)的,提交到appstore的應用不能包含動態(tài)庫,但是iOS8之后apple開放了這個限制,用戶可以在app中使用動態(tài)庫。 但是apple 審核中注明了,不允許動態(tài)下發(fā)代碼,所以通過更換app中的動態(tài)庫實現(xiàn)增量更新是行不通的(每個app提交后都是經(jīng)過簽名的,如果app使用了動態(tài)庫,也會同時簽名,在app校驗簽名通過才能運行,如果直接替換動態(tài)庫,簽名這關過不了。對于不發(fā)布到appstore的應用可以參考這里通過framework動態(tài)更新)。我們常用的第三方庫管理工具carthage打包的framework就是動態(tài)庫。
mac中區(qū)分兩種庫
那么我們平時如何知道使用的庫是動態(tài)庫還是靜態(tài)庫呢?最簡單的方式就是mac電腦上的finder可以識別兩種庫,如下圖:


從上圖可以看出,動態(tài)庫在finder中的預覽圖跟其他可執(zhí)行文件一樣是exec形式,而靜態(tài)庫沒有對應預覽圖。
這里還有個問題,上面我們已經(jīng)分析到,動態(tài)庫中不會直接將外部引用鏈接進去,所以對于較大的工程一般靜態(tài)庫都比動態(tài)庫小很多,但是上圖例子中我沒有添加任何源碼的情況下,空的動態(tài)庫比靜態(tài)庫大不少,用sublime打開發(fā)現(xiàn)動態(tài)庫中很大部分都是00, 這是怎么回事有待求證。
使用庫
上面提到了動態(tài)庫比靜態(tài)庫好的方面,那么我們在項目中應該怎么取舍?直接用動態(tài)庫嗎?
這里需要注意,動態(tài)庫雖然文件小,占據(jù)空間小,但是我們在app中使用時由于與可執(zhí)行文件是獨立放在ipa中,因為在運行時在加載到內存中,所以xcode工程配置(如下圖)需要將二進制文件嵌入進去,這樣實際上我們生成的app的大小比使用靜態(tài)庫會大。

如果是靜態(tài)庫,這步可以省略。
所以實際項目中可以根據(jù)需求判斷,是想要運行時啟動時加載庫少,占用內存少,啟動快? 還是app安裝文件?。ㄟ^大會被appstore限制,后期可能影響其他需求的添加)?
我們一般何時需要使用第三方庫:
- 需要輪子
開發(fā)中,有一個重要原則:D R Y 對應著 don‘t repeat yourself
也就是說我們要避免重復的代碼,不僅是自己重復的代碼要做好重構和復用,也避免寫一些別人已經(jīng)寫好的代碼,用好第三方庫。 - 協(xié)同開發(fā)
以一個大型工程為例:
如果一個大型工程可能包含消息 空間 voip電話 公眾號 圈子 等很多功能模塊時,這些模塊都屬于不同小團隊負責,這個大工程需要加載所有這些模塊,需要編譯迅速,主線版本穩(wěn)定,通常都要各個模塊需要獨立工程管理,主工程通過加載各個子工程的靜態(tài)庫來編譯運行,這樣每個小模塊的開發(fā)人員只需要關注自己模塊內部的工程,編譯速度快,整個團隊的效率高。 - 共享代碼或者以庫為產(chǎn)品
就像我們使用他人的源碼或庫一樣,我們也可以把自己積累的比較通用的源碼分享出去,讓其他人集成來提高開發(fā)進度,或者將我們的源碼編譯成庫,商業(yè)運作形式變賣。這時我們就需要確定自己的協(xié)議,也就是說別說使用我們的源碼或庫需要履行哪些責任,怎么付費等