1. 程式人生 > >iOS靜態庫 【.a 和framework】【超詳細】

iOS靜態庫 【.a 和framework】【超詳細】

一、什麼是庫?

庫是共享程式程式碼的方式。

庫從本質上來說是一種可執行程式碼的二進位制格式,可以被載入記憶體中執行。庫分靜態庫和動態庫兩種。
iOS中的靜態庫有 .a 和 .framework兩種形式;動態庫有.dylib 和 .framework 形式,後來.dylib動態庫又被蘋果替換成.tbd的形式。

二、靜態庫與動態庫的區別?

靜態庫: 連結時完整地拷貝至可執行檔案中,被多次使用就有多份冗餘拷貝。

動態庫: 連結時不復制,程式執行時由系統動態載入到記憶體,供程式呼叫,系統只加載一次,多個程式共用,節省記憶體。[ios暫時只允許使用系統動態庫];

靜態庫和動態庫是相對編譯期和執行期的:靜態庫在程式編譯時會被連結到目的碼中,程式執行時將不再需要改靜態庫;而動態庫在程式編譯時並不會被連結到目的碼中,只是在程式執行時才被載入,因為在程式執行期間還需要動態庫的存在。


總結:同一個靜態庫在不同程式中使用時,每一個程式中都得匯入一次,打包時也被打包進去,形成一個程式。而動態庫在不同程式中,打包時並沒有被打包進去,只在程式執行使用時,才連結載入(如系統的框架如UIKit、Foundation等),所以程式體積會小很多,但是蘋果不讓使用自己的動態庫,否則稽核就無法通過。

三、iOS裡靜態庫形式?

.a和.framework

四、iOS裡動態庫形式?

.dylib和.framework

五、framework為什麼既是靜態庫又是動態庫?

系統的.framework是動態庫,我們自己建立的.framework是靜態庫。

六、a與.framework有什麼區別?

.a是一個純二進位制檔案,.framework中除了有二進位制檔案之外還有資原始檔。

.a檔案不能直接使用,至少要有.h檔案配合,.framework檔案可以直接使用。

.a + .h + sourceFile = .framework。

建議用.framework.

七、為什麼要使用靜態庫?

方便共享程式碼,便於合理使用。

實現iOS程式的模組化。可以把固定的業務模組化成靜態庫。

和別人分享你的程式碼庫,但不想讓別人看到你程式碼的實現。

開發第三方sdk的需要。

八、製作靜態庫時的幾點注意:

1注意理解:無論是.a靜態庫還.framework靜態庫,我們需要的都是二進位制檔案+.h+其它資原始檔的形式,不同的是,.a本身就是二進位制檔案,需要我們自己配上.h和其它檔案才能使用,而.framework本身已經包含了.h和其它檔案,可以直接使用。

2圖片資源的處理:兩種靜態庫,一般都是把圖片檔案單獨的放在一個.bundle檔案中,一般.bundle的名字和.a或.framework的名字相同。.bundle檔案很好弄,新建一個資料夾,把它改名為.bundle就可以了,右鍵,顯示包內容可以向其中新增圖片資源。

3category是我們實際開發專案中經常用到的,把category打成靜態庫是沒有問題的,但是在用這個靜態庫的工程中,呼叫category中的方法時會有找不到該方法的執行時錯誤(selector not recognized),解決辦法是:在使用靜態庫的工程中配置other linker flags的值為-ObjC。

4如果一個靜態庫很複雜,需要暴露的.h比較多的話,就可以在靜態庫的內部建立一個.h檔案(一般這個.h檔案的名字和靜態庫的名字相同),然後把所有需要暴露出來的.h檔案都集中放在這個.h檔案中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出來就可以了。

九、建立.a靜態庫

第一步,新建工程。一般使用工程名就使用庫的名稱,比如我這裡用LIB來建立靜態庫,我的工程名就取名為LIB,建立的.a靜態庫就是LIB.a。

第二步,刪除.m檔案,保留.h檔案, 一般靜態庫都有一個總的.h檔案,方便外部匯入標頭檔案。然後匯入需要打包的原始檔。

第三步,先用真機,編譯一次,再用模擬器編譯一次。就可以生成.a檔案(必須先用真機要不然,不能生成)。

第四步,Xcode生成的.a檔案預設沒有匯出.h檔案。需要自己新增。

第五步,匯出Products靜態庫的配置(其實不用設定此步驟,如果真機編譯的話,生成匯出的時候系統預設會變成Releasse[但是模擬器不會(如果不改這裡 得需要把Debug設定為NO)])

注意:如果第五步中,不將Build Configuration改為Release,則打包出來的靜態庫會存於【Debug-iphoneos】和【Debug-iphonesimulator】兩個資料夾下。
我們一般都使用Release模式,因為程式最終釋出之後是Release版的,所以靜態庫也是在Release模式下使用。

第六步,合成模擬器的架構【預設:模擬器編譯只會生成對應的1種架構,真機編譯會合成兩種架構】

如果第六步這裡,設定為YES,那麼編譯出來的.a靜態庫就只包含當前裝置的架構。


舉個例子:如果我們選擇iPhone 5模擬器【Command+B】編譯,則編譯出來的.a靜態庫只能用iPhone4s~5模擬器跑程式, 用iPhone5s~6plus,則會報找不到x86_64的libFMDB庫。

設定為 NO 之後,【Command+B】不管選擇哪個【模擬器】,則都會把【386   : 32位架構   4S ~ 5】【x86_64 : 64位架構   5S ~ 現在的機型】的架構都打包合併。

【注】【真機】不設定 [Build Active Architecture Only] 預設會自動合併的armv7 和amr64架構 。但是 armv7s架構被蘋果放棄了,真機要想合併armv7s的話需要進行如下操作再編譯。(其實沒必要設定這個)

第七步,合併架構【真機和模擬器】

真機和模擬器合併: lipo -create 靜態庫1.a(路徑) 靜態庫2.a(路徑) -output 新靜態庫.a 

第八步,資源包的問題

 1. 靜態庫的資源, 都應該放到字尾為.bundle的資料夾中 --> 避免檔案與本地檔案重名被覆蓋, 導致載入資原始檔出錯【注:要載入bundel路徑】

 2. 靜態庫打包時, 並不會打包資原始檔 --> 需要手動拖出去

 一. 經典報錯:

 找不到符號在XX架構上

 Undefined symbols for architecture x86_64(armv7/armv7s/amr64/i386)

 二. 架構的分類

 1、模擬器架構: 2種

        i386   : 32位架構  4S ~ 5

        x86_64 : 64位架構   5S ~ 現在的機型

 2、真機架構: 3種

        armv7 : 32位架構    3GS ~ 4S

        armv7s: 特殊的架構   5 ~ 5C   (此架構有問題, 有的程式變得更快, 有的程式變得更慢)

        amr64 : 64位架構    5S ~ 現在的機型

 64位/32位: 記憶體定址不同

 三. 如何檢視靜態庫架構

 找到Products資料夾, 如果.a檔案是黑色, 右鍵開啟 到 Products資料夾

終端中 lipo -info

 

 Generic iOS Device編譯出來的OS可用, 有2種架構:armv7/ arm64 (不包含armv7s: 特殊的架構)

 iPhone6S模擬器編譯出來的: x86_64

 iPhone4S模擬器編譯出來的: i386

 (不設定Build Active Architecture Only的情況下真機編譯2種架構, 模擬器編譯:對應的1種架構)

 四. 合成架構

 一般來說, 只需要前兩步即可

 1. 模擬器架構的合成: Target --> Build Settings --> Build Active Architecture Only(是否只編譯當前架構) --> Debug 改為NO(改為NO, 模擬器就可以直接合成2種架構)

 2. 真機和模擬器合併: lipo -create 靜態庫1.a 靜態庫2.a -output 新靜態庫.a

 3.* armv7s這個架構, 在2014年10月份的xcode版本更新中, 取消了預設匯出此架構. 可以不用支援此架構. 

    如果要支援, 需要手動新增3個架構.

五. Debug和Release版本

 一般來說, 我們應該釋出的是release版本.

 debug:除錯版本, 系統本身也會有一些除錯程式碼. 此版本體積會稍大, 執行會稍慢

 release: 釋出版本, 系統會去除除錯程式碼, 體積變小, 執行速度變快. 對使用者來說沒有明顯的感覺

 六. 到底要不要合成多個架構

 真機和模擬器合成的好處: 除錯會非常方便, 缺點是體積會變大(一種架構就佔用一部分體積).

 真機和模擬器不合成的好處:體積小,  缺點是除錯稍顯麻煩.

 七. 資源包的問題

 1. 靜態庫的資源, 都應該放到字尾為.bundle的資料夾中 --> 避免檔案重名被覆蓋, 導致載入資原始檔出錯

 2. 靜態庫打包時, 並不會打包資原始檔 --> 需要手動拖出去

十、建立framework靜態庫

第一步、新建工程。一般使用工程名就使用庫的名稱

第二步、匯入需要打包的資原始檔,同時把資原始檔需要外界訪問的.h檔案匯入到系統推薦的.h中

第三步、真機,模擬器編譯一下。可能會需要輸入AppleID 。匯出的檔案沒有包含.h

第四步、匯出.h

第五步、可以檢視一下 沒合併模擬器架構之前包含幾個同.a(可跳過此步)(真機包含兩個,模擬器包含一個)

第六步、合成架構【同.a五六步詳細看上邊】

第七步,合併架構【真機和模擬器】【注意 合併之後的動態/靜態庫要與原來的名稱一致。不然用的時候編譯報錯】

第八步、動態庫變靜態庫【預設是動態】好處是將來使用時不需要設定新增動態庫(也就是下邊的方法)

最後步、

Framework製作後預設是動態庫使用時需要設定一下: Tarteg --> General --> Embedded Binaries --> 需要新增對應的動態庫 【注意 要是製作的時候更改為靜態庫的話,就不用執行此方法】

謝謝。