iOS 靜態庫和動態庫的基本介紹和使用

iOS 靜態庫和動態庫的基本介紹和使用

轉載自:http://blog.csdn.net/vbirdbest/article/details/52869237

什麼是庫 ?


庫就是程式程式碼的集合,將N個檔案組織起來,是共享程式程式碼的一種方式。


庫的分類


  • 開源庫:原始碼是公開的,可以看到每個實現檔案(.m檔案)的實現,例如GitHub上的常用的開源庫:AFNetworking、SDWebImage等;
  • 閉源庫:不公開原始碼,是經過編譯後的二進位制檔案,看不到具體的實現。閉源庫又分為:靜態庫 和 動態庫

靜態庫存在的形式

  • .a
  • .framework

動態庫的存在形式

  • .dylib
  • .framework

靜態庫和動態庫的區別

  • .a檔案肯定是靜態庫,.dylib肯定是動態庫,.framework可能是靜態庫也可能是動態庫;
  • 靜態庫在連結時,會被完整的複製到可執行檔案中,如果多個App都使用了同一個靜態庫,那麼每個App都會拷貝一份,缺點是浪費記憶體。類似於定義一個基本變數,使用該基本變數是是新複製了一份資料,而不是原來定義的;
  • 動態庫不會複製,只有一份,程式執行時動態載入到記憶體中,系統只會載入一次,多個程式共用一份,節約了記憶體。類似於使用變數的記憶體地址一樣,使用的是同一個變數;
  • 但是專案中如果使用了自己定義的動態庫,蘋果是不允許上架的,在iOS8.0以後蘋果開放了動態載入.dylib的介面,用於掛載.dylib動態庫

靜態庫的運用場景

  • 保護自己的核心程式碼,如訊飛語言摸索了好多年探索出的結果當然要保護起來了,都公開了公司還怎麼生存。
  • 將MRC的專案打包成靜態庫,可以在ARC下直接使用,不用轉換。如別人使用MRC寫的開源庫,放到自己ARC專案中,需要對每個檔案加一個編譯引數 -fno-objc-arc,這樣相對來說麻煩,將整個工程打包成靜態庫直接放到專案中即可,也不用對每個檔案新增編譯選項。

靜態庫的特點

.a .h

.a : 可以看做所有.m檔案加密後的一個二進位制檔案
.h : 標頭檔案使用者暴漏可用的介面(方法)


製作靜態庫.a

  1. 新建靜態庫New—>Project—>Cocoa Touch Static Library
    這裡寫圖片描述
  2. 寫一個方法模擬一個功能
    這裡寫圖片描述

這裡寫圖片描述
3. 指定靜態庫需要公開的標頭檔案
這裡寫圖片描述
4. 選擇模擬器iphone6s, 然後 Command B 編譯靜態庫, 可以看到iFly.a檔名由紅色變為黑色,右鍵 Show In Finder
這裡寫圖片描述
5. 使用靜態庫,新建一個工程,然後將iFly.a 和 include標頭檔案拖進專案中,然後使用iFly.h公開的方法,然後選擇iphone6s 模擬器執行
這裡寫圖片描述


製作靜態庫相關問題

  1. 我們在製作靜態庫是使用的模擬器iPhone6s, 如果對測試專案TestStaticLib使用iPhone6s執行完全沒問題,但是如果選擇模擬器為iphon5和Generic iOS Device進行編譯(command B)就會 報錯:Undefined symbols for architecture i386(未定義的符號i386架構)

    這裡寫圖片描述

這裡寫圖片描述


架構是神馬東東?

CPU架構是CPU廠商給屬於同一系列的CPU產品定的一個規範,主要目的是為了區分不同型別CPU的重要標示。模擬器上的架構和真機上的架構是不一樣的,模擬器和模擬器之間,真機和真機之間的架構也是不同的。如果靜態庫的架構和測試專案對應的模擬器或真機上的架構不對應就會報“未定義的符號XXX架構”, 由此可以得出模擬器上的靜態庫!

模擬器架構

  • iPhone4s ~ 5 : i386
  • iPhone5s ~ 7Plus : x86_64

真機架構

  • 3GS~4s : armv7
  • 5/5c : armv7s(armv7相容armv7s)
  • 5s ~ 6sPlus : arm64

使用iPhone6s打包的靜態庫架構是:x86_64, 測試專案選擇的是模擬器iPhone5對應的架構是:i386, 架構不匹配所以報Undefined symbols for architecture i386

檢視靜態庫對應的架構
在終端上使用命令: lipo -info Xxx.a
這裡寫圖片描述

input file libiFly.a is not a fat file:輸入檔案libiFly.a不是一個胖檔案,胖檔案是指只支援一個架構,不相容其它架構。


讓靜態庫支援所有模擬器對應的架構

Build Settings—>Build Active Architecture Only(只構建活躍的架構)—-> NO
什麼叫只構建活躍的架構?所謂活躍的架構是指當前選中的模擬器的架構,你選中的就稱為活躍的,你沒有選中的那些稱為不活躍的,重新編譯(Command B)一下靜態庫,可以拖到測試專案中選中各種模擬器進行測試都是正常的。

這裡寫圖片描述

重新編譯之後檢視靜態庫支援的架構,同時支援i386和x86_64,是一個胖檔案
這裡寫圖片描述


靜態庫的版本

靜態庫有4種版本:

  • 除錯版本:不會對程式碼進行優化
    • 模擬器版本
    • 真機版本
  • 釋出版本 :會對程式碼進行優化,執行效率相對除錯版本快,但不會有明顯的差別
    • 模擬器版本
    • 真機版本

選中模擬器編譯預設是除錯版-模擬器版本,選中Generic iOS Device預設是是除錯版本-真機版本

生成Release版本的靜態庫

首先編輯靜態庫對應的Scheme為Release,然後分別選擇模擬器或真機Command B 進行編譯

這裡寫圖片描述

這裡寫圖片描述

合併靜態庫

我們知道模擬器版本的靜態庫和真機版的是不能通用的,那麼怎樣讓一個靜態庫即支援模擬器又支援真機呢?

使用終端 lipo -create Xxx1.a Xxx2.a -output Xxx.a
這裡寫圖片描述
合併後同時支援i386、armv7、x86_64、arm64 這四種架構,合併就是將兩個.a檔案相加,合併後檔案的大小是兩個檔案之和。通常自己製作靜態庫給別人用一般是給兩個釋出版對應的模擬器和真機版本,不給合併版本,因為使用者想合並可以自己進行合併,如果給使用者一個合併版的,使用者則無法分解的。


製作靜態庫.framework

  1. 建立靜態庫工程,預設是動態庫,修改Build Settings—>Mach-O Type:Static Library
    這裡寫圖片描述
    這裡寫圖片描述
  2. 建立一個類,模擬靜態庫中的一個功能
    這裡寫圖片描述
  3. 公開標頭檔案
    這裡寫圖片描述
    這裡寫圖片描述
  4. 將其他需要公開的標頭檔案包含到總的標頭檔案中
    這裡寫圖片描述
    iFly.h 是一個總的標頭檔案,可以將其他需要公開的檔案都統一寫到總的標頭檔案中,使用者在使用的時候就匯入這一個總的標頭檔案即可
  5. 修改Build Settings–>Build Active Architecture Only: NO, 將Scheme修改為Release 分別選擇真機和模擬器進行編譯 Command B, 右鍵iFly.framework Show In Finder

    這裡寫圖片描述
    這裡寫圖片描述
  6. 檢視Release版本的模擬器和真機支援的架構
    這裡寫圖片描述
  7. 建立一個專案進行測試,將Release-iphonesimulator下的iFly.framework拖進到工程中,並呼叫靜態庫中的方法
    這裡寫圖片描述

製作動態庫.framework

製作動態庫和上面步驟差不多,不同的是在編譯framework時要指定Mach-O Type: Dynamic Type
這裡寫圖片描述

將.framework檔案新增到General—> Embedded Binaries 中,不新增會報錯

這裡寫圖片描述

這裡寫圖片描述

.bundle

在使用第三方庫時有可能會有一個.bundle檔案,.bundle其實是一個物理資料夾,裡面可以放圖片等資源。因為.bundle是一個物理資料夾,所以當被拖入到專案中就不會和自己專案中的圖片重名。

.a 和 .framework

使用.a時需要同時將.a 和 .h 檔案拖入到工程中,使用.framework時直接將這個資料夾拖入進去即可,因為.framework資料夾中已經包含了.h檔案。

.a .h .bundle = .framework, 使用.framework更加方便

靜態庫如何一邊開發一邊進行除錯

建立一個複合專案
1. 建立一個普通工程Single View Application
2. 在TARGETS中新增一個靜態庫
這裡寫圖片描述這裡寫圖片描述這裡寫圖片描述

這裡寫圖片描述
3. 在普通Target中新增目標依賴 Target Dependencies,選中剛才的靜態庫
4. 在普通Target–> Link Binary With Libraries 中新增靜態庫
這裡寫圖片描述
5. 在ViewController#viewDidLoad中測試
這裡寫圖片描述
這裡寫圖片描述
6. 至此靜態庫開發好,測試完成後修改靜態庫對應的Build Active Architecture Only:NO
7. 修改Scheme為Release
8. 暴漏標頭檔案:Build Phases —> Copy Files
9. 分別對Release的真機和模擬器進行Command B

Swift不支援靜態庫只支援動態庫

Swift is not supported for static libraries.

Swift暴漏方法的方式:Swift不像OC那樣有標頭檔案,將Swift中的類和方法用public修飾就可以將類和方法暴漏出來
public class Tool : NSObject {
public func tool(){
print(“Test”)
}
}