ios靜態庫的使用

來源:互聯網
上載者:User

ios靜態庫的使用
ios靜態庫的使用 2014-03-11 22:24 3906人閱讀 評論(0) 收藏 舉報

ios的靜態庫檔案是*.a,如果需要使用它,我今天學的簡單的方法,可通過,簡單說說,如果有一個A手機項目,一個B的靜態庫項目,A想使用B.a,按以下的步驟:

1、在A項目裡面拖進B項目。在B的product下面會看見紅色的B.a,表示還沒有編譯通過(在工程設定裡添加上你需要匯出的.m檔案)。

2、選擇好需要編譯的對象,B下的某模擬器或者是B下的真機上進行編譯(模擬器上產生的靜態庫和真機上產生的不能混用)

3、在A裡面建立一個檔案夾(new group),裡面拖進你需要B裡面匯入的標頭檔。

4、在A的framework裡加入編譯好的.a靜態庫,編譯通過的就不會是紅色。

5、在需要使用的地方#import 所需的標頭檔。ok了!

 

下面二篇,是別人寫的產生和使用靜態庫,裡面還有資源的Binder 方法,可借鑒!

一、IOS開發----產生靜態庫(.a)

 

由於iPhone控制項的極度匱乏和自訂群組件在重用上的限制,在過去的項目中我們積累了大量的“純程式碼”組件——因為IB本身的限制,我們無法把這些組件封裝為IB組件庫(本來我們想通過分發xib檔案的方式重用這些組件,但最終發現這根本不可能,蘋果的Plug-in編程不支援iPhone)。

最終我們想到了靜態庫。雖然這仍然還是一種比較原始的複用方式,但起碼我們可以隱藏組件的原始碼。

下面, 我們使用iPhone靜態庫把自訂群組件CheckButton 進行進一步的封裝。(組件的實現參考前一篇博文《自訂控制項複選框和單選框的實現》)

一、實現靜態庫

建立工程, 選擇 Library 下的 “ Cocoa Touch Static Library ” 。給工程命名,例如:yhyLibrary。

複製CheckButton組件的4個源檔案:CheckButton.h、CheckButton.m、RadioGroup.h、RadioGroup.m到Classes目錄下,同時把CheckButton的4個資源檔:check.png、uncheck.png、radio.png、unradio.png,複製到工程檔案夾。

按下 ? +b編譯,在Products目錄下即產生一個 .a檔案。

二、 建立資源束

靜態庫中並不能包含資源檔,雖然我們已經把4個資源檔(.png檔案)拷貝到靜態庫工程中,但實際上這些.png是不會添加到target的,也就是說編譯結果中並不包含這些資源,因此如果此時調用靜態庫,所有的資源(字串、圖片)都是缺失的。

我們可以把資源建立成單獨的束(Bundle)。

建立工程“ Mac OS X -> Framework & Library -> Bundle ”,命名為:yhyLibraryBundle。

然後把上面4個.png檔案拷進Resouces中去。編譯,產生yhyLibraryBundle.bundle檔案。

返回靜態庫工程,建立一個類:Utils 。

編輯Utils.h:

#define MYBUNDLE_NAME @ "yhyLibraryBundle.bundle"

#define MYBUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: MYBUNDLE_NAME]

#define MYBUNDLE [NSBundle bundleWithPath: MYBUNDLE_PATH]

NSString * getMyBundlePath( NSString * filename);

編輯Utils.m:

#import "Utils.h"

NSString* getMyBundlePath( NSString * filename)

{

NSBundle * libBundle = MYBUNDLE ;

if ( libBundle && filename ){

NSString * s=[[libBundle resourcePath ] stringByAppendingPathComponent : filename];

NSLog ( @"%@" ,s);

return s;

}

return nil ;

}

函數getMyBundlePath可以取得束yhyLibraryBundle中具體資源的絕對檔案路徑,如:

/Users/kmyhy/Library/Application Support/iPhone Simulator/4.2/Applications/8213652F-A47E-456A-A7BB-4CD40892B66D/yhyLibTest.app/yhyLibraryBundle.bundle/Contents/Resources/radio.png

同時,修改CheckButton.m中的代碼,匯入Utils.h標頭檔,把其中擷取圖片的代碼由imageNamed修改為imageWithContentsOfFile,如:

[ icon setImage :[ UIImage imageWithContentsOfFile : getMyBundlePath ( checkname )]];

即通過絕對路徑讀取圖片資源。

除了這種方法,我們還可以有一個簡單辦法,就是把4個資源檔直接拷貝到你調用靜態庫的應用工程中(不需要修改靜態庫代碼)。

 

三、靜態庫調用

1、添加靜態庫

建立Window-based Application工程,給工程命名,如yhyLibraryTest。

右鍵點 Frameworks->Add->Existing Files.. ,把靜態庫工程的yhyLibrary.xcodeproj檔案 添加到當前工程(不要選擇 Copy items ) 。

 

選中添加進來的yhyLibrary.xcodeproj檔案,勾選“include to target”選項,如,打上最後一個小勾:

 

2、添加Direct Dependencies(即引用工程)

類似於Visual Studio中的引用工程,目的是便於在本工程中直接編輯所引用的靜態庫工程,以便對靜態庫進行修改。

在“ Targets ”目錄下選擇“ FirstLibraryTest ”,點擊“info”按鈕,調出目標的屬性視窗,切換到“General”欄,點擊“ Direct Dependencies ”下方的“ + ”按鈕,將工程靜態庫libyhyLibrary添加到Direct Dependencies中,結果如:

 

 

3、添加標頭檔搜尋路徑

開啟工程的info視窗,在Build欄中找到Header Search Paths,添加字串“../yhyLibrary”。

4、 引用資源束

在target的Copy Bundle Resources上右鍵,選擇“Add->Existing File…”,把前面產生的yhyLibraryBundle.bundle束添加到工程。

5、調用靜態庫中的類

編輯 application:( UIApplication *)application didFinishLaunchingWithOptions: 方法中的代碼:

// 選項按鈕組

RadioGroup * rg =[[ RadioGroup alloc ] init ];

// 第 1 個選項按鈕

CheckButton * cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 60 , 260 , 32 )];

// 把選項按鈕加入按鈕組

[ rg add :cb];

cb. label . text = @"★" ;

cb. value =[[ NSNumber alloc ] initWithInt : 1 ];

// 把按鈕設定為選項按鈕樣式

cb. style = CheckButtonStyleRadio ;

// 加入視圖

[ self . window addSubview :cb];

[cb release ]; //add 後,會自動持有,可以釋放

// 第 2 個選項按鈕

cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 100 , 260 , 32 )];

[ rg add :cb];

cb. label . text = @"★★" ;

cb. value =[[ NSNumber alloc ] initWithInt : 2 ];

cb. style = CheckButtonStyleRadio ;

[ self . window addSubview :cb];

[cb release ];

// 第 3 個選項按鈕

cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 140 , 260 , 32 )];

[ rg add :cb];

cb. label . text = @"★★★" ;

cb. value =[[ NSNumber alloc ] initWithInt : 3 ];

cb. style = CheckButtonStyleRadio ;

[ self . window addSubview :cb];

[cb release ];

運行結果如下:

 

6、分發靜態庫

將產生的.a檔案和.bundle檔案打包分發給其他人。


二、使用靜態連結庫(Xcode4.6.2)

 

一、理論部分

 

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

 

靜態連結庫適用於:

1.你想將一部分以後都不會修改的代碼打包,供其他項目使用

2.你想將一部分代碼封裝起來給別人用,又不願別人看到你的實現方法

 

二、實踐部分

 

如何製作靜態連結庫(以下簡稱lib):

1。如果是新工程。建立工程的時候選Framework&Library -> cocoa touch static library,就直接建立了一個靜態連結庫工程,預設會有兩個跟工程名相同的.h和.m,繼續添加檔案,m都會自動加入到Build Phases->Compile Source中,表示這些代碼會被編譯進lib中,你可以刪掉你不希望被編譯的。

2. 如果是項目工程,想抽取一個lib出來,就add target,也是選Framework&Library -> cocoa touch static library。在xcode navigator裡會多一個檔案夾,和你新建立的target同名。同樣,你可以在Build Phases->Compile Source裡,添加你希望加入到lib中的檔案。

 

下面:建立兩個單視圖模版項目DemoOne,DemoTwo,其中,我想把DemoTwo作為靜態庫,然後在DemoOne中使用:


a、開啟DemoTwo

滑鼠選擇:

然後 點擊Add Target,選擇 Framework & Library -> Cocoa Touch Static Library -> 建立一個名字叫MyLib的庫:

 

其中,MyLib這個target,就是我們想對外提供的庫,這個庫的對外提供的介面,是我們自己可以任意控制的,當然可以加多個target,每個target靜態庫可以提供不同介面,我這裡只做一個靜態庫MyLib。讓MyLib這個target 和 DemoTwo 建立時的預設target DemoTwo功能類似,所以還要給MyLib 添加 Frameworks:

 

然後開始編寫MyLib這個庫想對外提供哪些功能了,在DemoTwo項目中建立一個group,命名為LibMethod,並在其中建立三個類Func1,Funk2,UILabelEX,其中實現的代碼都很簡單,列印log而已。

Func1 和 Func2 類似,拿Func1舉例:

 

@interface Func1 : NSObject

- (void) func1Log;

@end

#import "Func1.h"

@implementation Func1

- (void) func1Log {

NSLog(@"Func1 log");

}

@end

 

UILabelEX 是一個類別擴充,因為之前有人說,類別擴充不能放到靜態庫中,所以親自實驗一下:

 

#import

@interface UILabel (TestColor)

- (void) testMethodColor;

@end

#import "UILabelEX.h"

@implementation UILabel (TestColor)

- (void) testMethodColor {

NSLog(@"testMethodColor");

}

@end

 

並且確保MyLib 的 Compile Sources 中包含我們剛剛建立類的 .m檔案,因為這裡添加了哪些.m檔案,就相當於MyLib靜態庫對外提供了什麼介面,如果沒有加入,就要手動點擊+來加入了:

 

然後關閉DemoTwo項目,開啟DemoOne項目,開啟DemoTwo專案檔夾,把其中的 DemoTwo.xcodeproj 拖拽到DemoOne中:

 

然後給DemoOne添加庫,選擇我們在DemoTwo中建立的MyLib:

 

如果libMyLib.a為紅色,表明DemoTwo,沒有編譯產生libMyLib.a,不要慌,這個是小事情:

 

理論(在編譯之前,在target的scheme中選build configuration選擇模擬器,然後編譯。

 

注意,你用device模式編譯出的lib只能真機運行,模擬器模式編譯出的lib只能用於模擬器調試。然後找到編譯出lib,複製到需要它的工程裡。

如果你希望一個lib既可以在模擬器上運行,又可以在真機上運行,那就各編譯一次吧,把兩個lib都找到,用命令把兩個lib合并成一個,命令是:lipo -create sim.a dev.a -ouput libXX.a 合并產生的libXX.a就可以兩用了。

把lib和新工程裡需要引用的標頭檔都添加進新工程,這樣就可以了。)

 

我這裡以使用模擬器為例,來讓DemoTwo編譯產生lib

 

這個有個細節問題,就是你產生的lib想用在真機,還是模擬器?很簡單, 首先選擇 Mylib,然後在點擊其響應下的 Edit Scheme,最上邊可以選擇是模擬器還是真機,然後build一下:

 

此時發現DemoOne中的,依賴庫正常了吧:

 

然後就開始讓DemoOne來使用DemoTwo提供的借口吧:

單首先要在DemoOne中引入下DemoTwo中的介面,DemoOne建立group ,名字 lib,然後把DemoTwo中的介面.h檔案,以引用的形式拖拽到lib檔案夾中(如果不以引用形式,當DemoTwo中介面代碼改變時,DemoOne中的介面檔案不會隨著改變):

 

到此時,工作基本完成了,然後在DemoOne的 ViewController中實現如下代碼:

 

#import "ViewController.h"

#import "Func1.h"

#import "Func2.h"

@implementation ViewController

- (void)viewDidLoad

{

[superviewDidLoad];

Func1 *obj1 = [[Func1alloc]init];

[obj1 func1Log];

 

Func2 *obj2 = [[Func2alloc]init];

[obj2 func2Log];

}

@end

編譯及運行,不出意外,應該有log列印了,說明我們基本成功了。

 

不過是不是少了點是嗎?對 #import "UILabelEX.h" 這個類還沒使用呢,這個類是對UILabel的類型擴充:

 

#import

@interface UILabel (TestColor)

- (void) testMethodColor;

@end

#import "UILabelEX.h"

@implementation UILabel (TestColor)

- (void) testMethodColor {

NSLog(@"testMethodColor");

}

@end

那使用一下吧:

 

UILabel *obj3 = [[UILabel alloc]init];

[obj3 testMethodColor];

然後編譯並運行,發現項目crash了,原因:

-[UILabel testMethodColor]: unrecognized selector sent to instance 0x7574190

 

代碼裡明明 UILabel可以找到testMethodColor,但實際上沒找到這個方法,這個地方還有個細節,答案在這裡:http://developer.apple.com/library/mac/#qa/qa1490/_index.html

 

DemoOne的 build setting中,搜尋 Other Linker Flags,找到設定後,在其中添加一個參數 -ObjC,再編譯及運行,貌似一切都OK了。

 

 

其它:

1、如果你沒有完全按步驟來弄,可能會出現如下錯誤,一般用模擬器做的項目可能會遇到這個問題:

 

  1. Undefined symbols for architecture i386:
  2. "_OBJC_CLASS_$_RequestServer", referenced from:
  3. objc-class-ref in ListViewController.o
  4. objc-class-ref in SettingsViewController.o
  5. ld: symbol(s) not found for architecture i386
  6. clang: error: linker command failed with exit code 1 (use -v to see invocation) 不要擔心,去DemoTwo的lib中,把對外介面的.m檔案添加進去:

     

     

    2、如果做真機使用的 lib,可能會遇到arm7相關的錯誤,我暫時沒遇到,引用別人的解決辦法如下(我沒親自實驗過):

     

    Xcode4.5.2、iOS6應用中靜態庫不支援armv7s的解決方案

     

    錯誤詳細資料:
    ld: file is universal (3 slices) but does not contain a(n) armv7s slice: /zhangyg/XXX/XXX/libs/libxxx.a for architecture armv7s

    clang: error: linker command failed with exit code 1 (use -v to see invocation)


    解決方案如下:

     

     

    方法一:把Build Active Architecture Only的值設定為Yes

    方法二:把Valid Architectures中的armv7s刪除
    方法三:如果有libxxx.a的原始碼再編譯一個libxxx.a的armv7s版本,然後合并到之前的libxxx.a中

     

    3、模擬器運行正常,但真機會crash,列印如下錯誤:

    dyld: lazy symbol binding failed: Symbol not found: _objc_setProperty_atomic_copy
    Referenced from: /var/mobile/Applications/DFCB17A5-52AC-41CD-9ECB-94415C7D36F3/kalagame-demo.app/kalagame-demo
    Expected in: /usr/lib/libobjc.A.dylib


    dyld: Symbol not found: _objc_setProperty_atomic_copy
    Referenced from: /var/mobile/Applications/DFCB17A5-52AC-41CD-9ECB-94415C7D36F3/kalagame-demo.app/kalagame-demo
    Expected in: /usr/lib/libobjc.A.dylib

    解決辦法:

     

    這個錯誤就是說App可執行檔裡引用了objc_setProperty_nonatomic或objc_setProperty_atomic這些函數。但是代碼裡顯然沒有直接調用這2個函數,應該是系統在編譯時間產生的。經過Debug調試發現總是在設定一個對象的屬性時出現這個錯誤。而這個對象的類定義在靜態庫裡面,所以我看了看靜態庫。
    經過排查,發現導致這一問題的原因是這個靜態庫的Deployment Target設定成了6.0。因為objc_setProperty_nonatomic和objc_setProperty_atomic是iOS6中新增的函數,所以如果靜態庫的Deployment Target設定成iOS6,那麼編譯後就會使用objc_setProperty_nonatomic和objc_setProperty_atomic這些新的API。由於iOS5中沒有這些API,運行後將會崩潰。

    結論
    靜態庫在編譯時間,Deployment Target一定要低於和等於工程的Deployment Target。否則容易出現低版本iOS運行不相容的情況。


     

    4、突然項目要更改靜態庫項目的工程名稱,於是右件靜態庫項目可執行檔(藍顏色的那個),快顯功能表中選 Show File Inspector,然後XIB屬性修改入口彈出,可以修改項目名稱,但修改完項目名稱之後,發現靜態庫提供的幾個介面失效了。

    報錯:Undefined symbols for architecture armv7:

    解決辦法:在引用靜態庫的項目設定中,重新添加靜態庫檔案,就是那個 XXX.a 檔案。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.