靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)
一、靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的存在形式
靜態(tài)庫(kù): .a 和 .framework
動(dòng)態(tài)庫(kù): .dylib 和 .framework
靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)在使用上的區(qū)別
靜態(tài)庫(kù):鏈接時(shí),靜態(tài)庫(kù)會(huì)被完整地復(fù)制到可執(zhí)行文件中, 被多次使用就有多份冗余拷貝 (左圖所示)
動(dòng)態(tài)庫(kù):鏈接時(shí)不復(fù)制,程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)加載到內(nèi)存,供程序調(diào)用,系統(tǒng)只加載一次,多個(gè)程序共用,節(jié)省內(nèi)存。
需要注意的是:項(xiàng)目中如果使用了自制的動(dòng)態(tài)庫(kù),不能被上傳到 AppStore!
靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)中之所以都有.framework,是因?yàn)樘O(píng)果自己的framework是動(dòng)態(tài)庫(kù),以供我們開(kāi)發(fā)者使用,但是,我們自制時(shí),制作的是.framework的靜態(tài)庫(kù)。
二、什么是.a、.bundle、.framework?
在iOS中靜態(tài)庫(kù)以.a和.framework的形式存在,動(dòng)態(tài)庫(kù)以.dylib和.framework的形式存在。
之所以.framework既可能是動(dòng)態(tài)庫(kù)又可能是靜態(tài)庫(kù),是因?yàn)樘O(píng)果公司禁止用戶(hù)級(jí)App使用動(dòng)態(tài)庫(kù),而自己卻又堂而皇之的使用動(dòng)態(tài)庫(kù),這就造成了iOS中系統(tǒng)級(jí)的.framework是動(dòng)態(tài)庫(kù),用戶(hù)級(jí)的.framework是靜態(tài)庫(kù)。
二者區(qū)別不大,.a是純二進(jìn)制文件,.a文件不能單獨(dú)使用,至少要有.h文件配合,而.framework除了二進(jìn)制文件外,還包含一些資源文件(頭文件,plist等),由于自身包含了頭文件,所以.framework可以單獨(dú)使用。
.a和.framework兩種靜態(tài)庫(kù),通常都是把需要用的到圖片或者xib文件存放在一個(gè)bundle文件中,而該bundle文件的名字和.a或.framework的名字相同。關(guān)于bundle文件的制作方法,后面第七大點(diǎn)介紹。
三、靜態(tài)庫(kù)使用的必要性
1>. 代碼的共享與重用
2>. 程序模塊化
3>. 分享給別人代碼庫(kù)時(shí)代碼隱藏
4>. 開(kāi)發(fā)第三方SDK
四、編譯生成靜態(tài)庫(kù)時(shí),模式:debug和release的區(qū)別
靜態(tài)庫(kù)分為真機(jī)—Debug(調(diào)試)版本、真機(jī)—Release(發(fā)布)版本、模擬器—Debug版本、模擬器—Release版本;開(kāi)發(fā)中一般都打包Release(發(fā)布)版本,將真機(jī)和模擬器版本合并,提供外界。
DEBUG,好處在于Xcode開(kāi)啟很多服務(wù)來(lái)監(jiān)控錯(cuò)誤,讓程序員來(lái)調(diào)試用,但是耗性能。RELEASE,好處在于則相反。
所以,建議:
——在生成靜態(tài)庫(kù)的時(shí)候,可以把上面Run的參數(shù)調(diào)整為Release,這樣節(jié)省內(nèi)存,運(yùn)行速度快。
——在平時(shí)用Run調(diào)試的時(shí)候,在DEBUG下運(yùn)作正常后,在發(fā)布程序之前可修改Run的參數(shù)為Release,再運(yùn)行一下模擬發(fā)布的情況,因?yàn)橛袝r(shí)候在Debug下正常,在Release下會(huì)崩潰,兩者對(duì)錯(cuò)誤的敏感度不同。
五、制作.a靜態(tài)庫(kù)
創(chuàng)建工程:
在Build Settings -->link ->Other Linker Flags中(xcode 8.2)工程自動(dòng)添加了-ObjC。
在使用已經(jīng)制作的靜態(tài)庫(kù)的工程中,若是靜態(tài)庫(kù)中有分類(lèi),也需要加上-ObjC。
接著需要做:在copy files中添加所有的.h文件,這些.h都是暴露在外面的:
先注意檢查下面Release是否為NO:Yes表示只編譯選中模擬器設(shè)備對(duì)應(yīng)的架構(gòu),No則為編譯所有模擬器設(shè)備支持的cup架構(gòu)(Debug版本同理),選擇NO,然后分別在模擬器和真機(jī)下Command+B編譯一下,會(huì)看到Products文件夾下的.a文件變?yōu)楹谏?,這個(gè).a文件就是我們想要得到的靜態(tài)庫(kù):
(親自測(cè):release默認(rèn)為NO,debug默認(rèn)為YES。debug為YES情況下,在模擬器iphone6上編譯,得到的庫(kù)在7P上可以用,但是在5上就會(huì)崩潰,調(diào)整debug為NO,7和5都不崩潰)
合并模擬器的.a 和真機(jī)的.a(選Generic iOS Device 進(jìn)行編譯即可得到真機(jī)):
- 通過(guò)終端打開(kāi)路徑/Users/**/Library/Developer/Xcode/DerivedData/,選擇對(duì)應(yīng)的工程文件夾,就是進(jìn)入制作靜態(tài)庫(kù)的工程。(在工程中的.a -- show in finder, 會(huì)看到Release-iphoneos和Release-iphonesimulator文件夾,分別是真機(jī)和模擬器的.a文件)
- 合并真機(jī)和模擬器.a文件,在終端輸入以下命令行:lipo -create 模擬器.a文件的路徑 真機(jī).a文件的路徑 -output 合并后的保存路徑(例:lipo -create /Users/shelin/Library/Developer/Xcode/DerivedData/StaticLib/Build/Products/Release-iphoneos/libxxx.a /Users/shelin/Library/Developer/Xcode/DerivedData/StaticLib/Build/Products/Release-iphonesimulator/libxxx.a -output /Users/shelin/Desktop/StaticLib.a)最終會(huì)在桌面得到一個(gè)合并后的StaticLib.a文件,再將暴露出來(lái)的.h頭文件一起復(fù)制出來(lái)。
3.使用:只需將.a和暴露出來(lái)的.h頭文件導(dǎo)入工程目錄下就可供外界使用。
制作的另外一種方式:
不用創(chuàng)建一個(gè)新的工程,在源代碼的項(xiàng)目里,新建一個(gè)target:
在和項(xiàng)目并列地方有TestAProduct文件夾,把需要編譯成.a的文件拖入這個(gè)文件夾里面,添加TestAProduct需要暴露的頭文件,選擇TestAProduct目標(biāo)工程運(yùn)行,則在Products里面會(huì)有生成的.a庫(kù)。(TestProduct的target里面的Compoile Sources需要有所有需要的.m的引用,不然運(yùn)行不會(huì)生成,拖入之后,正常的target->TestPro也是可以運(yùn)行的,因?yàn)樗锩娴腃ompoile Sources有.m的引用)
六、制作.framework靜態(tài)庫(kù)
- 創(chuàng)建.framework的靜態(tài)和動(dòng)態(tài)庫(kù)都是:
靜態(tài)和動(dòng)態(tài)庫(kù)的選擇在于(linking-->Mach-o Type的選擇):
- 創(chuàng)建工程后,這里的Headres是自攜帶的:
(把.h文件都放到public里面,不然會(huì)報(bào)找不到的錯(cuò)誤)
編譯生成真機(jī)和模擬器的framework靜態(tài)庫(kù)的方法和.a的方法是一樣的,接下來(lái)就是合成真機(jī)和模擬器的庫(kù),這里和制作.a時(shí)的合并有點(diǎn)不同就是:
![Upload 0001.png failed. Please try again.]
這里合并用到的是里面的wgj_makeFramework:
![Upload 002.png failed. Please try again.]
例如:lipo -create /Users/wgj/Library/Developer/Xcode/DerivedData/wgj_makeFramework-gevmzbcgwfblmsewnayqsoutdztu/Build/Products/Debug-iphoneos/wgj_makeFramework.framework/wgj_makeFramework /Users/wgj/Library/Developer/Xcode/DerivedData/wgj_makeFramework-gevmzbcgwfblmsewnayqsoutdztu/Build/Products/Debug-iphonesimulator/wgj_makeFramework.framework/wgj_makeFramework -output /Users/wgj/Desktop/newFramework
其中,output后面的newFramework不是提前建好的文件夾,生成之前,桌面上不需要做操作。
這樣,生成后,直接把桌面的生成的東東替換庫(kù)里面的最后層次的wgj_makeFramework就好了,newFramework名字最好改為wgj_makeFramework。
七、制作.bundle
1、bundle資源庫(kù)的特點(diǎn)
Bundle是靜態(tài)的,也就是說(shuō),我們包含到包中的資源文件作為一個(gè)資源包是不參加項(xiàng)目編譯的。也就意味著,bundle包中不能包含可執(zhí)行的文件。它僅僅是作為資源,被解析成為特定的2進(jìn)制數(shù)據(jù)
-
創(chuàng)建
01.png
3、加入你需要編譯在bundle中的資源文件(若是圖片,需帶后綴.png)。
當(dāng)然,默認(rèn)的配置也是可以的,如果你需要特定的優(yōu)化或者特定的路徑配置,你可以進(jìn)行下面第4步的配置。
-
進(jìn)行可選設(shè)置
資源包只需要編譯不需要安裝:所以設(shè)置skip install 為YES;然后刪除安裝路徑如下:
02.png - 編譯即可得到.bundle文件
6.導(dǎo)入項(xiàng)目應(yīng)用,調(diào)用方式,例如圖片的三種加載的方式:
//1.
// imageV.image = [UIImage imageNamed:@"wgj_bundle.bundle/Contents/Resources/0001.png"];
//2.
// NSString *fileS = [[NSBundle mainBundle] pathForResource:@"wgj_bundle.bundle/Contents/Resources/0001" ofType:@"png"];
// imageV.image = [UIImage imageWithContentsOfFile:fileS];
//3.
NSString *path = [[NSBundle mainBundle] pathForResource:@"wgj_bundle" ofType:@"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:path];
NSString *file = [bundle pathForResource:@"0001" ofType:@"png"];
imageV.image = [UIImage imageWithContentsOfFile:file];
注意:在制作靜態(tài)庫(kù)時(shí),若把靜態(tài)庫(kù)里面的圖片(正常的圖片,不是bundle里面的)暴露出來(lái),則靜態(tài)庫(kù)工程和用到靜態(tài)庫(kù)的工程可以直接用,[UIImage imageNamed:@"has.png"];如果是不暴露出來(lái),則靜態(tài)庫(kù)工程和用到靜態(tài)庫(kù)的工程都用不了(靜態(tài)庫(kù)工程用了無(wú)效)。若是在制作靜態(tài)庫(kù)的時(shí)候,用.bundle文件封裝圖片資源,靜態(tài)庫(kù)制作時(shí),把.bundle文件暴露在外界,則也是一種方法,在外界通過(guò)路徑加載也是可以使用到圖片的(.bundle文件不暴露在外界,圖片在靜態(tài)庫(kù)中,也是使用無(wú)效的)
(資源文件都打包放在這里。在制作Framework的時(shí)候不可以把圖片直接放在項(xiàng)目中,否則制作好之后圖片是一張一張的出現(xiàn)在項(xiàng)目中非常亂,需要新建一個(gè)bundle將圖片放進(jìn)去,這里的bundle提供整個(gè)SDK的圖片資源。
注意:圖片放進(jìn)bundle之后不可以用[UIImage ImageWithName:]讀取圖片。要先找到bundle包再拿圖片)
八、制作.framework動(dòng)態(tài)庫(kù)
制作.framework的動(dòng)態(tài)庫(kù)和制作.framework的靜態(tài)庫(kù)基本相同,其不同點(diǎn):
制作庫(kù)時(shí)這個(gè)地方改為:Dynamic Library,另外在使用已制作動(dòng)態(tài)庫(kù)的 工程中添加:
這個(gè)圖片中的Embedded Binaries 里面的庫(kù)是自制的動(dòng)態(tài)庫(kù),需要手動(dòng)添加。
當(dāng)然在使用靜態(tài)庫(kù)時(shí),需要把這個(gè)Embedded Binaries 中的已手動(dòng)添加的動(dòng)態(tài)庫(kù)去掉。(在導(dǎo)入自己制作的動(dòng)態(tài)庫(kù)時(shí),需要在Embedded Binaries中導(dǎo)入,不然會(huì)報(bào)錯(cuò):image not found。此時(shí)這個(gè)動(dòng)態(tài)庫(kù)會(huì)跟靜態(tài)庫(kù)一樣被拷貝到目標(biāo)程序中進(jìn)行編譯,蘋(píng)果又把這種Framework叫做Embedded Framework)