轉載自: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
- 新建靜態庫New—>Project—>Cocoa Touch Static Library
- 寫一個方法模擬一個功能
3. 指定靜態庫需要公開的頭文件
4. 選擇模擬器iphone6s, 然後 Command + B 編譯靜態庫, 可以看到iFly.a文件名由紅色變爲黑色,右鍵 Show In Finder
5. 使用靜態庫,新建一個工程,然後將iFly.a 和 include頭文件拖進項目中,然後使用iFly.h公開的方法,然後選擇iphone6s 模擬器運行
製作靜態庫相關問題
- 我們在製作靜態庫是使用的模擬器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
- 創建靜態庫工程,默認是動態庫,修改Build Settings—>Mach-O Type:Static Library
- 創建一個類,模擬靜態庫中的一個功能
- 公開頭文件
- 將其他需要公開的頭文件包含到總的頭文件中
iFly.h 是一個總的頭文件,可以將其他需要公開的文件都統一寫到總的頭文件中,用戶在使用的時候就導入這一個總的頭文件即可 - 修改Build Settings–>Build Active Architecture Only: NO, 將Scheme修改爲Release 分別選擇真機和模擬器進行編譯 Command + B, 右鍵iFly.framework Show In Finder
- 查看Release版本的模擬器和真機支持的架構
- 創建一個項目進行測試,將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”)
}
}