ios 開發中 動態庫 與靜態庫的區別

軍說網事發表於2016-02-27

 使用靜態庫的好處

1,模組化,分工合作

2,避免少量改動經常導致大量的重複編譯連線

3,也可以重用,注意不是共享使用

 

動態庫使用有如下好處:

1使用動態庫,可以將最終可執行檔案體積縮小

2使用動態庫,多個應用程式共享記憶體中得同一份庫檔案,節省資源

3使用動態庫,可以不重新編譯連線可執行程式的前提下,更新動態庫檔案達到更新應用程式的目的。

從1可以得出,將整個應用程式分模組,團隊合作,進行分工,影響比較小。

等其他好處,

從2可以看出,其實動態庫應該叫共享庫,那麼從這個意義上來說,蘋果禁止iOS開發中使用動態庫就可以理解了:

因為在現在的iPhone,iPodTouch,iPad上面程式都是單程式的,也就是某一時刻只有一個程式在執行,那麼你寫個共享庫,

       ----共享給誰?(你使用的時候只有你一個應用程式存在,其他的應該被掛起了,即便是可以同時多個程式執行,別人能使用你的共享庫裡的東西嗎?你這個是給你自己的程式定製的。)

       ----目前蘋果的AppStore不支援模組更新,無法更新某個單獨檔案(除非自己寫一個更新機制:有自己的服務端放置最新動態庫檔案)

至於蘋果為啥禁止ios開發使用動態庫我就猜到上面倆原因

 

 

深入理解iPhone靜態庫

      在實際的程式設計過程中,通常會把一些公用函式製成函式庫,供其它程式使用,一則提搞了程式碼的複用;二則提搞了核心技術的保密程度。所以在實際的專案開發中,經常會使用到函式庫,函式庫分為靜態庫和動態庫兩種。和多數人所熟悉的動態語言和靜態語言一樣,這裡的所謂靜態和動態是相對編譯期和執行期的:靜態庫在程式編譯時會被連結到目的碼中,程式執行時將不再需要改靜態庫;而動態庫在程式編譯時並不會被連結到目的碼中,只是在程式執行時才被載入,因為在程式執行期間還需要動態庫的存在。

  iPhone官方只支援靜態庫聯編。

深入理解framework(框架,其實相當於靜態框架,不是動態庫)

打包framework還是一個比較重要的功能,可以用來做一下事情:

(1)封裝功能模組,比如有比較成熟的功能模組封裝成一個包,然後以後自己或其他同事用起來比較方便。

(2)封裝專案,有時候會遇到這個情況,就是一家公司找了兩個開發公司做兩個專案,然後要求他們的專案中的一個巢狀進另一個專案,此時也可以把唄巢狀的專案打包成framework放進去,這樣比較方便。

 

我們為什麼需要框架(Framework)?

要想用一種開發者友好的方式共享庫是很麻煩的。你不僅僅需要包含庫本身,還要加入所有的標頭檔案,資源等等。

蘋果解決這個問題的方式是框架(framework)。基本上,這是含有固定結構幷包含了引用該庫時所必需的所有東西的資料夾。不幸的是,iOS禁止所有的動態庫。同時,蘋果也從Xcode中移除了建立靜態iOS框架的功能。

Xcode仍然可以支援建立框架的功能,重啟這個功能,我們需要對Xcode做一些小小的改動。

把程式碼封裝在靜態框架是被app store所允許的。儘管形式不同,本質上它仍然是一種靜態庫。

框架(Framework)的類別

大部分框架都是動態連結庫的形式。因為只有蘋果才能在iOS裝置上安裝動態庫,所以我們無法建立這種型別的框架。

靜態連結庫和動態庫一樣,只不過它是在編譯時連結二進位制程式碼,因此使用靜態庫不會有動態庫那樣的問題(即除了蘋果誰也不能在iOS上使用動態庫)。

“偽”框架是通過破解Xcode的目標Bundle(使用某些指令碼)來實現的。它在表面上以及使用時跟靜態框架並無區別。“偽”框架專案的功能幾乎和真實的框架專案沒有區別(不是全部)。

“嵌入”框架是靜態框架的一個包裝,以便Xcode能獲取框架內的資源(圖片、plist、nib等)。

本次釋出包括了建立靜態框架和“偽”框架的模板,以及二者的“嵌入”框架。

用哪一種模板?

本次釋出有兩個模板,每個模板都有“強”“弱”兩個類別。你可以選擇最適合一種(或者兩種都安裝上)。

最大的不同是Xcode不能建立“真”框架,除非你安裝靜態框架檔案xcspec在Xcode中。這真是一個遺憾(這個檔案是給專案使用的,而不是框架要用的)。

簡單第

簡單說,你可以這樣決定用哪一種模板:

·        如果你不想修改Xcode,那麼請使用“偽”框架版本

·        如果你只是想共享二進位制(不是專案),兩種都可以

·        如果你想把框架共享給不想修改Xcode的開發者,使用“偽”框架版本

·        如果你想把框架共享給修改過Xcode的開發者,使用“真”框架版本

·        如果你想把框架專案作為另一個專案的依賴(通過workspace或者子專案的方式),請使用“真”框架(或者“偽”框架,使用-framework——見後)

·        如果你想在你的框架專案中加入其他靜態庫/框架,並把它們也連結到最終結果以便不需要單獨新增到使用者專案中,使用“偽”框架

“偽”框架

“偽”框架是破解的“reloacatableobject file”(可重定位格式的目標檔案, 儲存著程式碼和資料,適合於和其他的目標檔案連線到一起,用來建立一個可執行目標檔案或者是一個可共享目標檔案),它可以讓Xcode編譯出類似框架的東西——其實也是一個bundle。

“偽框架”模板把整個過程分為幾個步驟,用某些指令碼去產生一個真正的靜態框架(基於靜態庫而不是reloacatable object file)。而且,框架專案還是把它定義為wrapper.cfbundle型別,一種Xcode中的“二等公民”。

因此它跟“真”靜態框架一樣可以正常工作,但當存在依賴關係時就有麻煩了。

依賴問題

如果不使用依賴,只是建立普通的專案是沒有任何問題的。但是如果使用了專案依賴(比如在workspace中),Xcode就悲劇了。當你點選“Link Binary With Libraries”下方的’+’按鈕時,“偽框架”無法顯示在列表中。你可以從你的“偽”框架專案的Products下面將它手動拖入,但當你編輯你的主專案時,會出現警告:

warning: skipping file"/somewhere/MyFramework.framework" (unexpectedfile type"wrapper.cfbundle" in Frameworks & Libraries build phase)

並伴隨“偽”框架中的連結錯誤。

幸運的是,有個辦法來解決它。你可以在”OtherLinker Flags”中用”-framwork”開關手動告訴linker去使用你的框架進行連結:

-framework MyFramework

警告仍然存在,但起碼能正確連結了。

新增其他的庫/框架

如果你加入其他靜態(不是動態)庫/框架到你的“偽”框架專案中,它們將“連結”進你最終的二進位制框架檔案中。在“真”框架專案中,它們是純引用,而不是連結。

你可以在專案中僅僅包含標頭檔案而不是靜態庫/框架本身的方式避免這種情況(以便編譯通過)。

“真”框架

“真”框架各個方面都符合“真”的標準。它是真正的靜態框架,正如使用蘋果在從Xcode中去除的那個功能所建立的一樣。

為了能建立真正的靜態框架專案,你必需在Xcode中安裝一個xcspec檔案。

如果你釋出一個“真”框架專案(而不是編譯),希望去編譯這個框架的人必需也安裝xcspec檔案(使用本次釋出的安裝指令碼),以便Xcode能理解目標型別。

注意:如果你正在釋出完全編譯的框架,而不是框架專案,終端使用者並不需要安裝任何東西。

我已經提交一個報告給蘋果,希望他們在Xcode中更新這個檔案,但那需要一點時間.OpenRadarlink here

加其他靜態庫/框架

如果你加入其他靜態(不是動態)庫/框架到你的“真”框架專案,它們只會被引用,而不會象“偽”框架一樣被連結到最終的二進位制檔案中。

從早期版本升級

如果你是從Mk6或者更早的版本升級,同時使用“真”靜態框架,並且使用Xcode4.2.1以前的版本,請執行uninstall_legacy.sh以解除安裝早期用於Xcode的所有修正。然後再執行install.sh,重啟Xcode。如果你使用Xcode4.3以後,只需要執行install.sh並重啟Xcode。

安裝

分別執行Real Framework目錄或Fake Framework目錄下的install.sh指令碼進行安裝(或者兩個你都執行)。

重啟Xcode,你將在新專案嚮導的Framework&Library下看到StaticiOS Framework(或者Fake Static iOS Framework)。

解除安裝請執行unistall.sh指令碼並重啟Xcode。

建立一個iOS框架專案

1.  建立新專案。

2.  專案型別選擇Framework&Library下的Static iOS Framework(或者Fake Static iOSFramework)。

3.  選擇“包含單元測試”(可選的)。

4.  在target中加入類、資源等。

5.  凡是其他專案要使用的標頭檔案,必需宣告為public。進入target的Build Phases頁,展開Copy Headers項,把需要public的標頭檔案從Project或Private部分拖拽到Public部分。

編譯你的 iOS 框架

1.  選擇指定target的scheme

2.  修改scheme的Run配置(可選)。Run配置預設使用Debug,但在準備部署的時候你可能想使用Release。

3.  編譯框架(無論目標為iOS device和Simulator都會編譯出相同的二進位制,因此選誰都無所謂了)。

4.  從Products下選中你的framework,“show in Finder”。

在build目錄下有兩個資料夾:(yourframework).framework and (your framework).embeddedframework.

如果你的框架只有程式碼,沒有資源(比如圖片、指令碼、xib、coredata的momd檔案等),你可以把(yourframework).framework 分發給你的使用者就行了。如果還包含有資源,你必需分發(yourframework).embeddedframework給你的使用者。

為什麼需要embedded framework?因為Xcode不會查詢靜態框架中的資源,如果你分發(yourframework).framework, 則框架中的所有資源都不會顯示,也不可用。

一個embedded framework只是一個framework之外的附加的包,包括了這個框架的所有資源的符號連結。這樣做的目的是讓Xcode能夠找到這些資源。

使用iOS 框架

iOS框架和常規的Mac OS動態框架差不多,只是它是靜態連結的而已。

在你的專案中使用一個框架,只需把它拖僅你的專案中。在包含標頭檔案時,記住使用尖括號而不是雙引號括住框架名稱。例如,對於框架MyFramework:

#import<MyFramework/MyClass.h>

 

 

使用問題

Headers Not Found

如果Xcode找不到框架的標頭檔案,你可能是忘記將它們宣告為public了。參考“建立一個iOS框架專案”第5步。

No Such Product Type

如果你沒有安裝iOS UniversalFramework在Xcode,並企圖編譯一個universal框架專案(對於“真”框架,不是“假”框架),這會導致下列錯誤:

target specifies product type"com.apple.product-type.framework.static",but there"s no suchproduct type for the "iphonesimulator" platform

為了編譯“真”iOS靜態框架,Xcode需要做一些改動,因此為了編譯“真”靜態框架專案,請在所有的開發環境中安裝它(對於使用框架的使用者不需要,只有要編譯框架才需要)。

The selected run destination is not valid for this action

有時,Xcode出錯並載入了錯誤的active設定。首先,請嘗試重啟Xcode。如果錯誤繼續存在,Xcode產生了一個壞的專案(因為Xcode4的一個bug,任何型別的專案都會出現這個問題)。如果是這樣,你需要建立一個新專案重來一遍。

連結警告

第一次編譯框架target時,Xcdoe會在連結階段報告找不到資料夾:

ld: warning: directory notfound foroption"-L/Users/myself/Library/Developer/Xcode/DerivedData/MyFramework-ccahfoccjqiognaqraesrxdyqcne/Build/Products/Debug-iphoneos"

此時,可以clean並重新編譯target,警告會消除。

Core Data momd not found

對於框架專案和應用程式專案,Xcode會以不同的方式編譯momd(託管物件模型檔案)。Xcode會簡單地在根目錄建立.mom檔案,而不會建立一個.momd目錄(目錄中包含VersionInfo.plist和.mom檔案)。

這意味著,當從一個embeddedframework的model中例項化NSManagedObjectModel時,你必需使用.mom副檔名作為model的URL,而不是採用.momd副檔名。

NSURL *modelURL = [[NSBundlemainBundle]URLForResource:@"MyModel" withExtension:@"mom"];

Unknown class MyClass in Interface Builder file.

由於靜態框架採用靜態連結,linker會剔除所有它認為無用的程式碼。不幸的是,linker不會檢查xib檔案,因此如果類是在xib中引用,而沒有在O-C程式碼中引用,linker將從最終的可執行檔案中刪除類。這是linker的問題,不是框架的問題(當你編譯一個靜態庫時也會發生這個問題)。蘋果內建框架不會發生這個問題,因為他們是執行時動態載入的,存在於iOS裝置韌體中的動態庫是不可能被刪除的。

有兩個解決的辦法:

 

     讓框架的終端使用者關閉linker的優化選項,通過在他們的專案的Other Linker Flags中新增-ObjC和-all_load。

     在框架的另一個類中加一個該類的程式碼引用。例如,假設你有個MyTextField類,被linker剔除了。假設你還有一個MyViewController,它在xib中使用了MyTextField,MyViewController並沒有被剔除。你應該這樣做:

在MyTextField中:

+ (void)forceLinkerLoad_ {}

在MyViewController中:

+(void) initialize{     [MyTextField forceLinkerLoad_]; }

他們仍然需要新增-ObjC到linker設定,但不需要強制all_load了。

第2種方法需要你多做一點工作,但卻讓終端使用者避免在使用你的框架時關閉linker優化(關閉linker優化會導致object檔案膨脹)。

unexpected file type "wrapper.cfbundle" in Frameworks&Libraries build phase

這個問題發生在把“假”框架專案作為workspace的依賴,或者把它當作子專案時(“真”框架專案沒有這個問題)。儘管這種框架專案產生了正確的靜態框架,但Xcode只能從專案檔案中看出這是一個bundle,因此它在檢查依賴性時發出一個警告,並在linker階段跳過它。

你可以手動新增一個命令讓linker在連結階段能正確連結。在依賴你的靜態框架的專案的OtherLinker Flags中加入:

-framework MyFramework

警告仍然存在, 但不會導致連結失敗。

Libraries being linked or not being linked into the finalframework

很不幸, “真”框架和“假”框架模板在處理引入的靜態庫/框架的工作方式不同的。

“真”框架模板採用正常的靜態庫生成步驟,不會連結其他靜態庫/框架到最終生產物中。

“假”框架模板採用“欺騙”Xcode的手段,讓它認為是在編譯一個可重定位格式的目標檔案,在連結階段就如同編譯一個可執行檔案,把所有的靜態程式碼檔案連結到最終生成物中(儘管不會檢查是否確實目的碼)。為了實現象“真”框架一樣的效果,你可以只包含庫/框架的標頭檔案到你的專案中,而不需要包含庫/框架本身。

Unrecognized selector in (some class with a category method)

如果你的靜態庫或靜態框架包含了一個模組(只在類別程式碼中宣告,沒有類實現),linker會搞不清楚,並把程式碼從二進位制檔案中剔除。因為在最終生成的檔案中沒有這個方法,所以當呼叫這個類別中定義的方法時,會報一個“unrecognizedselector”異常。

要解決這個,在包含這個類別的模組程式碼中加一個“假的”類。linker發現存在完整的O-C類,會將類別程式碼連結到模組。

我寫了一個標頭檔案 LoadableCategory.h,以減輕這個工作量:

#import"SomeConcreteClass+MyAdditions.h"

#import"LoadableCategory.h"  MAKE_CATEGORIES_LOADABLE(SomeConcreteClass_MyAdditions);  @implementation SomeConcreteClass(MyAdditions)

  ... 

@end

在使用這個框架時,仍然還需要在BuildSetting的Other Linker Flags中加入-ObjC。

執行任何程式碼前單元測試崩潰

如果你在Xcode4.3中建立靜態框架(或庫)target時,勾選了“withunit tests”,當你試圖執行單元測試時,它會崩潰:

Thread 1: EXC_BAD_ACCESS(code=2, address=0x0) 0 0x00000000 --- 15 dyldbootstrap:start(...)

這是lldb中的一個bug。你可以用GDB來執行單元測試。編輯scheme,選擇Test,在Info標籤中將偵錯程式Debugger從LLDB改為GDB。

 

 

 

相關文章