en

hi, it seems you are using microsoft internet explorer. it doesn't match web standard and causes problems browsing this site. please please please use mozilla firefox or google chrome instead. thank you!

zh

哦哦!您正在使用Internet Explorer 瀏覽器,它與我們的網頁標準並不相容,可能會導致畫面顯示不正常。
請改用 Mozilla Firefox 或者 Google Chrome 才能正常瀏覽本網站,謝謝!

6.23.2011

關於 Xcode 4 靜態函式庫 Static Library 的製作與使用

使用靜態函式庫 Static Library 這類的方法來撰寫程式除了可以讓程式有能被重複利用的特性之外,也能保護您程式不會被有心人士竄改或濫用,Static Library 可以將所有的實做檔 .m 全部包裝成一個副檔名為 .a 的靜態函式庫,當然這個函式庫是無法以正常的手法進行檢視和編輯,就如同在使用 Framework 時只能從眾多的標頭檔 Headers 中查看方法函式的名稱,卻無法得知具體的實做內容。下列文章會將 Xcode 4 靜態函式庫的分成三大部份,分別是環境設定、製作與使用,首先是設定的部份。

如何在 Xcode 4 中設定靜態函式庫 Static Library
首先在開啟新專案中找到 Cocoa Touch Static Library 來製作靜態函式庫的樣板,這是在 iOS SDK 的部份,如果您想要用 Mac OS X 的 BSD C Library 或是 STL C++ Library 等樣板,也同樣沒問題,關於這兩者間的差異稍後會做說明( 在 Mac OS X 的樣板中記得將函式庫類型由動態設 Dynamic 定成靜態 Static)。

使用 Cocoa Touch Static Library 開始新的專案

如果你想使用現有的程式來製作靜態函式庫,只需要為專案新增 Target (Add Target)並在 Build Phases 中的 Compile Sources 將要匯入靜態函式庫的實做檔案 .m 做好連結,其餘的步驟則完全相同。

在建立好專案(thelib)之後從 TARGETS 的選項 Build Settings 中可以看到這個靜態函式庫所使用的架構 Architectures 與 Base SDK,這個項目將決定這個靜態函式庫適用於什麼樣的架構,如果先前您所使用的樣板是 Mac OS X,那麼這裡會出現的就會是其他項目,如果這個靜態函式庫是要被應用於 iOS 上,則必須改成類似於下圖的設定值。

設定 Targets 的架構與 SDK 版本


如何在 Xcode 4 中製作靜態函式庫 Static Library
在完成環境設定之後,現在我們有了一個空的靜態函式庫,接下來我們為這個空的靜態函式庫加點功能,替這個專案新增一個 NSObject 的 Subclass,在其中使用類別方法實做一個印出字串的功能,程式瑪如下。

Furnace.h
#import <foundation/foundation.h>

@interface Furnace : NSObject {

}
+ (void)showMessage;
@end

Furnace.m
#import "Furnace.h"

@implementation Furnace
+ (void)showMessage {
    NSLog(@"Furnace iOS 中文學習網站");
}
@end

到目前為止整個專案的檔案配置應該會如下圖所示,在 Products 應該是呈現紅字,因為我們還沒對這專案中的 Target 進行編譯。

尚未進行編譯的靜態函式庫

在進行編譯產生靜態函式庫 libthelib.a 之前,還有一件非常重要的事情要做,就是要將 Build 的設定由 Debug 改成 Release,方法是在 Product 中選擇 Edit Scheme,或是直接在 Xcode 4 介面上點選 Scheme 也可以找到 Edit Scheme 項目,接著如下圖所示,將 Build Configuration 由 Debug 改成 Release,就可以對專案的 Target 進行編譯了。

將 Build Configuration 由 Debug 改成 Release

在編譯時請注意您的對象是實體機器,而不是模擬器,在出現 Build Succeeded 之後,原先的 libthelib.a 紅字也已經消失,代表這個靜態函式庫已經製作完成可以使用了,並能直接拖曳到其他專案內。

編譯完成的靜態函式庫

這裡有一個需要特別注意的地方,在 Xcode 中紅字是代表找不到檔案,而在 Xcode 4 的介面中,這個 libthelib.a 是針對實體機器的 Release 和 Debug 而定,如果您是使用模擬器進行編譯,就算編譯成功,在 Xcode 4 的介面上依然會出現紅字,如果要找到使用模擬器編譯出來的靜態函式庫檔案,可在使用者名稱下的 Library/Developer/Xcode/DerivedData/該專案名稱-亂數/Build/Products 中找到,並選擇 Release-iphonesimulator 資料夾中的靜態函式庫 .a 檔來使用。


如何在 Xcode 4 中使用靜態函式庫 Static Library
在使用靜態函式庫前,首先我們必須具備標頭檔 .h 與 靜態函式庫檔 .a,並將這兩個檔拖曳加入到您現在正在使用的專案的 Supporting Files 內,接下來就如同使用 Framework 一般 #import 標頭檔就可以直接使用,程式瑪如下。

#import "Furnace.h"
[Furnace showMessage];

在使用上如果標頭檔眾多或是不想拖曳標頭檔也可以採用檔案連結的方式,設定的方法是在 Targets 中找到 Header Search Paths,將其位置設定成剛剛靜態函式庫專案的位置即可(不需遞迴-尋找到子資料夾),如下圖。

設定引用靜態函式庫的目標位置

最後一個要注意的地方,也是大家常常會忽略的,就是在使用靜態函式庫時,如果是使用模擬器來執行,則你的靜態函式庫就必須是由模擬器所編譯產生,否則就會出現缺少 i386 架構的相關錯誤,如下圖。

使用錯誤的靜態函式庫執行結果

避免此問題出現的方法,就是使用模擬器編譯所產生的靜態函式庫 .a 檔,由模擬器編譯所產生的靜態函式庫檔位置,可參考本文中第二部份,如何在 Xcode 4 中製作靜態函式庫 Static Library 的最後一段。






12 則留言:

  1. 模擬器跟實機產生的static library只能給對應的使用, 這段收獲良多.
    有辦法滿足說一個static library同時給兩個環境使用嗎?
    若是不行的話, 那在一個專案同時加入兩個環境的lib後, 要怎樣區分模擬器跟實績分別使用各個同名但不同編譯環境下產生的lib?

    回覆刪除
    回覆
    1. Tom 您好:

      這方面我目前並沒有多做涉獵,不過應該可以透過使用 $(BUILT_PRODUCTS_DIR) 這個 Xcode 中的環境變數來幫助你。
      你可以在專案內對應的資料夾下放置不同的靜態函式庫,並且設定 Header Search Paths 的路徑為 $(BUILT_PRODUCTS_DIR),編譯器會自動辨識。

      另外,在「如何在 Xcode 4 中製作靜態函式庫 Static Library」中,有一小部分並沒有提到,就是編譯該靜態函式庫時你可以透過 Targets 的 Build Settings,找到 Installation Directory 設定(Deployment 項目中),同樣也可以使用 $(BUILT_PRODUCTS_DIR) 來做設定。

      希望有幫助到您!

      刪除
  2. 嗨牛奶大大 想請教你一下 有辦法能在輸出library時 一起把一些跟這library有關的檔案一起輸出嗎
    我也有把我的問題詳細寫這了 能的話麻煩幫我一下 thanks
    http://stackoverflow.com/questions/28337458/how-to-get-file-in-a-library-ios

    回覆刪除
    回覆
    1. 您好

      我記得lib沒辦法包這些而外的東西,你可以試試看使用相對路徑看看能不能存取!
      轉lib的目的就是reuse....不過你這樣...反而耦合性更高︿︿

      刪除
    2. 謝謝牛奶大大的回復
      我目前還是用bundle做 不知道是不是你相對路徑的意思了嗎?
      還是應該怎樣比較好呢

      刪除
    3. 您好:

      是的,沒錯唷!

      刪除
    4. 謝謝牛奶大大的回覆 你的網站真的讓我獲益良多!! 這邊想題外話問一個問題 如果要將資料傳到雲端server,是否有較方便的方法(http,jason...)?要怎樣設計才會讓server在相同頻寬下可以支援比較多的client呢?
      希望牛奶大大能給些建議 還是有哪些範例我能參考看看的? 謝謝^^

      刪除
    5. 你好:

      這.....我好難回答阿...

      如果要將資料傳到雲端server, - server 就是 server, 雲端...只是商人的花言巧語而已啦,client 和 server 之間溝通,透過網路,就算你server和client放在同一台主機上,server位置指向127.0.0.1 資訊還是要透過網路卡出去,這些東西你可以找一下「網路架構概論」相關資料,就算不會也沒關係一位大部分的東西,別人都已經做好了。


      是否有較方便的方法(http,jason...)? - http是傳輸協定..JSON(你打錯字了)是傳輸格式,這兩個好像搭不在一塊,你可以留意一下專有名詞後面有「p」的通常都是指 Protocol 協定,用來規定client和server雙方該怎麼建立連線,怎麼收資料像是tcp、udp、ftp等等,他們用途不同,所以真的要適用什麼要看你要做什麼東西,至於格式的話你提到的jason目前是比較常用的資料交換格式,好處是輕量查詢快速,但同樣也是要看你的應用範圍,也沒有誰好誰壞,這邊我真的沒辦法告訴你答案,抱歉。
      不過已我自己的經驗來說,寫一個大約20人的小型網路遊戲,直接用sql來做就可以了,在傳輸上玩家只有向server下sql語法查詢東西,撈回來的資料在自己處理。

      要怎樣設計才會讓server在相同頻寬下可以支援比較多的client呢? - 這個問題也是和上面一樣沒有絕對的答案,完全要看如何設計,這真的要講都可以寫一本書了...,像是主從式架構,叢集式分散式等等..很多很多,然後最後實作出來要做一個「壓力測試」,這才會有你問的問題,最多可以多少人使用?接下來才是解決負載平衡等等的相關衍生問題!

      看了一下google,有關 iOS JSON的文章蠻多的,你有興趣可以查閱看看,不過前提示你主機端有支援解析json格式的能力唷!
      我推薦這一篇,雖然是原文的不過寫的還算詳細
      http://www.appcoda.com/fetch-parse-json-ios-programming-tutorial/

      刪除
    6. 好謝謝牛奶大大詳細的回答 聽過你的建議後 現在的我比較有方向了 json是我手誤哈sorry
      再次感謝牛奶大大為我解惑><

      刪除
    7. 那祝你好運囉~~

      刪除
  3. 匿名5/07/2015

    嗨 牛奶大大~ 想請教你一下,如果在.a檔內要使用其他人所製作的.a檔案,該如何處理因為路徑不正確而產生的錯誤呢?

    或是如何將他人的.a檔案,編譯時包含在自己的.a檔內呢?

    回覆刪除
    回覆
    1. 您好:

      靜態函示庫在連結上有問題,你可以參考官方網站的作法試試看:
      https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Articles/configuration.html

      另外,也請先確認你目前的靜態函示庫是不是問題真的出在路徑錯誤上,而不是使用錯誤的靜態函示庫造成無法編譯。

      最後提到包含其他人使用的靜態函示庫,你也要把他的函示庫加到你的專案裡才可以用,你可以參考下列網址看看:
      http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

      刪除