在平常項目開發中,不管是爲了兩個公司項目上的業務交流仍是爲了減小項目的編譯時間,有的時候咱們會把項目中的私密內容打包成靜態庫,或者是把項目中變更較少一部分打包成靜態庫以便提升編譯效率,那麼下面咱們就來學習一下"iOS-靜態庫的建立與使用":windows
(一)iOS靜態庫、動態庫與Framework靜態庫與動態庫的區別:安全
(1)什麼是庫?架構
庫(Library)直白一點說就是一段編譯好的二進制代碼,加上頭文件就能夠供別人使用;(例如: iOS中Objective-C編譯下的.h和.m文件,打包靜態庫後會變爲.h和.a文件);app
(2)什麼是靜態庫?iphone
①靜態庫即靜態連接庫(例如: windows下的.lib、Mac和Linux下的.a);性能
②靜態庫在編譯的時候會被直接拷貝一份,複製到目標程序裏而且這段代碼在目標程序裏就不會在改變了,我猜這也是該庫叫"靜態庫"的緣由;學習
③靜態庫的利弊:優化
1)利: 靜態庫在編譯完成以後,庫文件實際上就沒有做用了,目標程序沒有外部依賴,直接就能夠運行;ui
2)弊: 弊端靜態庫會使用目標程序的體積增大;spa
(3)什麼是動態庫?
①動態庫即動態連接庫(例如: windows下的.dll、Mac下的.dylib、Linux下的.so);
②與靜態庫相反,動態庫在編譯時並不會被拷貝到目標程序中,目標程序中只會存儲指向動態庫的引用,等到程序運行時,動態庫纔會被真正加載進來;
③動態庫的利弊:
1)利: 不須要拷貝到目標程序中,不會影響目標程序的體積,並且同一份庫能夠被多個程序使用(由於這個緣由,動態庫也被稱做共享庫); 同時,編譯時才載入的特性,也可讓咱們隨時對庫進行替換,而不須要從新編譯代碼;
2)弊: 動態載入會帶來一部分性能損失,使用動態庫也會使得程序依賴於外部環境;若是環境缺乏動態庫或者庫的版本不正確,就會致使程序沒法運行;
(4)何時咱們會用到庫呢?
①某些代碼片斷須要給別人使用,可是咱們不但願別人看到源碼,就須要以庫的形式進行封裝,只暴露出頭文件;
②對於某些不會進行大的改動的代碼,咱們想減小編譯的時間,就能夠把它打包成庫,由於庫是已經編譯好的二進制了,編譯的時候只須要 Link 一下,不會浪費編譯時間;
說明:上面提到庫在使用的時候須要Link,Link 的方式有兩種:靜態和動態,因而便產生了靜態庫和動態庫("攻城獅"的思惟就是這麼簡單😄😄);
(5)iOS Framework?
①除了上面咱們提到iOS的.a和.dylib以外,Mac OS/iOS 平臺還可使用 Framework,Framework其實是一種打包方式,將庫的二進制文件、頭文件和有關的資源文件打包到一塊兒,方便管理和分發;在 iOS 8 以前,iOS 平臺不支持使用動態 Framework,開發者可使用的 Framework 只有蘋果自家的 UIKit.Framework,Foundation.Framework 等等;
②上面這種限制多是出於安全的考慮,換一個角度講,由於 iOS 應用都是運行在沙盒當中,不一樣的程序之間不能共享代碼,同時動態下載代碼又是被蘋果明令禁止的,沒辦法發揮出動態庫的優點,實際上動態庫也就沒有存在的必要了;
③因爲上面提到的限制,開發者想要在 iOS 平臺共享代碼,惟一的選擇就是打包成靜態庫 .a 文件,同時附上頭文件;可是這樣的打包方式不夠方便,使用時也比較麻煩,你們仍是但願共享代碼都能能像 Framework 同樣,直接扔到工程裏就能夠用;
④終於在日思夜盼便迎來了iOS對動態庫的支持: iOS 8/Xcode 6 推出以後,iOS 平臺添加了動態庫的支持,同時 Xcode 6 也原生自帶了 Framework 支持(動態和靜態均可以);
⑤可是說道這裏博主要告訴一下你們,iOS動態庫且用且珍惜(當心應用審覈被拒😄😄);
(二)切入主題"iOS靜態庫的建立":
(1)咱們先了解靜態庫文件的版本(四種):
①真機-Debug版本; ②真機-Release版本 ③模擬器-Debug版本 ④模擬器-Release版本;
(2)Debug(調試)版本特色:
①含完整的符號信息,以方便調試; ②不會對代碼進行優化;
(3)Release(發佈)版本特色:
①不會包含完整的符號信息; ②執行代碼是進行過優化的; ③大小會比Debug版本的略小 ④在執行速度方面,Release版本會快一些;
因此咱們通常開發中都打包Release(發佈)版本使用;
(4)再來了解一下iPhone設備CPU的架構簡介:
①模擬器: (4s~5: i386) (5s~6splus: x86_64)
②真 機: (3gs~4s: armv7) (5~5c: armv7s) (5s~6splus: arm64)[說明: 靜態庫只要支持了armv7,就能夠跑在armv7s的架構上];
(三)製做靜態庫-Debug版本:
(1)建立Cocoa Touch Static Library,新建項目選擇iOS ->Framework&Library -> Cocoa Touch Static Library,如圖1:
(2)點擊Next給工程命名如"Library"點擊Next, Xcode自動爲咱們建立了Library.h/.m文件以及相對應的目錄結構,如圖2所示:
(3)接下來咱們在工程的.h和.m裏面編寫功能實現的代碼(重在靜態庫的建立, 代碼粗略請你們無視😄😄):
1 "Library.h" 2 /** 十六進制轉二進制 */ 3 + (NSString *)getBinaryByhex:(NSString *)hex; 4 5 "Library.m" 6 + (NSString *)getBinaryByhex:(NSString *)hex { 7 NSMutableDictionary *hexDic = [[NSMutableDictionary alloc] init]; 8 9 hexDic = [[NSMutableDictionary alloc] initWithCapacity:16]; 10 [hexDic setObject:@"0000" forKey:@"0"]; 11 [hexDic setObject:@"0001" forKey:@"1"]; 12 [hexDic setObject:@"0010" forKey:@"2"]; 13 [hexDic setObject:@"0011" forKey:@"3"]; 14 [hexDic setObject:@"0100" forKey:@"4"]; 15 [hexDic setObject:@"0101" forKey:@"5"]; 16 [hexDic setObject:@"0110" forKey:@"6"]; 17 [hexDic setObject:@"0111" forKey:@"7"]; 18 [hexDic setObject:@"1000" forKey:@"8"]; 19 [hexDic setObject:@"1001" forKey:@"9"]; 20 [hexDic setObject:@"1010" forKey:@"A"]; 21 [hexDic setObject:@"1011" forKey:@"B"]; 22 [hexDic setObject:@"1100" forKey:@"C"]; 23 [hexDic setObject:@"1101" forKey:@"D"]; 24 [hexDic setObject:@"1110" forKey:@"E"]; 25 [hexDic setObject:@"1111" forKey:@"F"]; 26 27 NSString *binaryString=[[NSMutableString alloc] init]; 28 29 for (int i=0; i<[hex length]; i++) { 30 NSRange rage; 31 rage.length = 1; 32 rage.location = i; 33 NSString *key = [hex substringWithRange:rage]; 34 binaryString = [NSString stringWithFormat:@"%@%@",binaryString,[NSString stringWithFormat:@"%@",[hexDic objectForKey:key]]]; 35 } 36 return binaryString; 37 }
(4)編譯項目生成對應的靜態庫.a文件(在這裏注意一下細節):
①在工程編譯(Command+B)以前"標號爲②的框框中libLibrary.a"爲紅色(編譯以後爲黑色, 紅色表示一個虛擬的文件工程中找不到它),如圖3所示:
②編譯的過程當中咱們要選擇"模擬器編譯"和"真機編譯",如圖4圖5所示:
(5)右擊工程目錄下.a文件,查看編譯以後的靜態庫文件如圖6所示, 其中文件Debug-iphoneos裏面包含iPhone真機所須要的libLibrary.a靜態庫文件,文件Debug-iphonesimulator裏面包含的時iPhone模擬器所須要的libLibrary.a靜態庫文件,如圖7所示;
(6)分別查看打包好的模擬器與真機的靜態庫所支持的cpu架構:
在上面咱們介紹了iPhone設備CPU的架構,在這裏咱們就來查看咱們所打包的靜態庫是否符合iPhone設備包含的架構標準(提示: 若是不符合某些架構的標準,靜態庫運行到不一樣機型上回報錯誤),打開終端查看靜態庫的架構如圖8所示:
咱們找到緣由如圖9所示, 下面Debug:Yes表示只編譯選中模擬器對應的架構,No則爲編譯全部模擬器支持的cup架構(Debug的Yes狀態改成No便可);
再一次Command+B 編譯重複上面第(4)步的小步驟,就OK了,😄😄...
(7)合併靜態庫:
①爲何要合併靜態庫呢?
由於真機和模擬器的靜態庫,是不同的,不能同時適用在真機和模擬器上,但要知足這要求的話,要對編譯好的兩個靜態庫進行合併在使用;
②合併靜態庫的利弊?
1)利: 開發過程當中既能夠在真機上調試,也能夠在模擬器上調試;
2)弊: 若是靜態庫太大,合併打包後,會很是大,所以不少第三方的靜態庫的.a是區分版本的;
③打開終端合併靜態庫(終於快成功了😄😄...)如圖10所示:
其中完整的命令是:lipo -create /Users/apple/Library/Developer/Xcode/DerivedData/Library-bmlhmlslupltsqfkcfgmgqzducdy/Build/Products/Debug-iphoneos/libLibrary.a /Users/apple/Library/Developer/Xcode/DerivedData/Library-bmlhmlslupltsqfkcfgmgqzducdy/Build/Products/Debug-iphonesimulator/libLibrary.a -output /Users/apple/Desktop/libLibrary.a;
(8)靜態庫的使用:
將合併好的靜態庫文件(.a)和頭文件(.h)添加到工程裏面,調用靜態庫,結果以下(代碼粗略請你們無視...):
1 "ViewController.h" 2 @interface ViewController : UIViewController 3 4 @end 5 6 "ViewController.m" 7 #import "ViewController.h" 8 #import "Library.h" 9 10 @interface ViewController () 11 12 @end 13 14 @implementation ViewController 15 16 - (void)viewDidLoad { 17 [super viewDidLoad]; 18 // 十六進制轉二進制 19 NSLog(@"十六進制轉二進制: %@", [Library getBinaryByhex:@"F"]); 20 } 21 22 日誌打印輸入結果是: 23 靜態庫的使用[1006:40288] 十六進制轉二進制: 1111
(四)製做靜態庫-Release版本:
跟Debug版步驟同樣,只不過在編譯時,改下面的選項便可如圖12所示:
這時不論是真機仍是模擬器均可以編譯經過,正常運行;而使用者只能經過頭文件知道咱們提供的藉口,殊不知道實現文件中實現的細節,這有效地隱藏了本身的核心技術和機密內容;
(五)以上就是我對iOS靜態庫的理解與解釋,但願你們相互補充相互學習;