【翻譯】ios教程-建立靜態庫

做者:shede333
主頁:http://my.oschina.net/shede333
版權聲明:原創文章,版權聲明:自由轉載-非商用-非衍生-保持署名 | [Creative Commons BY-NC-ND 3.0][]html


本人英語也不是太好,翻譯質量不是過高,若有不妥之處,歡迎指點批評。ios

點此查看文章 英文原文shell

#建立IOS靜態庫xcode

若是你開發ios有一段時間了,你可能有許多想在你大部分項目裏重用的類和工具函數。網絡

重用代碼最容易的方法就是複製/黏貼,可是,這在代碼維護上很快就變成一個噩夢。 既然每個app都擁有一份 共享代碼 的拷貝,這就很難保證全部 拷貝的代碼共享代碼 在bug修正與更新的同步(一致性)。架構

這裏就使用靜態庫來拯救噩夢。靜態庫就是類、函數、定義(definitions)和資源的一個包,使用靜態庫,你能把代碼打包在一塊兒,而且在你全部的項目間共享。app

在這個教程,你將親身經歷使用兩種不一樣的方法建立你本身的通用靜態庫。框架

你應該熟悉Objective-C and iOS開發,才能理解大體上這個教程。
若是你對怎樣作一個相同的app 以及 圖像濾光代碼在庫裏的工做原理 感興趣,Core Image的相關知識雖然不是必須的,可是對你會頗有幫助。dom

準備開始高效的減小、重用和循環使用你的代碼吧!iphone

##爲何使用靜態庫

你可能由於不少緣由而建立靜態庫:

  • 你想要把你或者你團隊裏的成員編寫的類打包在一塊兒,便於合理的使用,而且很容易與周圍的人分享。
  • 你想要讓全部通用的代碼集中到一塊兒,便於你對代碼的bug修復與更新。
  • 你想和一些人分享你的代碼庫,可是你不想要他們看到你的代碼。
  • 隨着開發時間的進展,你想要作一個版本庫的快照。

在這個教程裏,假設你已經看過**Core Image Tutorial**這個教程,而且理解了如何使用一些照片處理效果的代碼。

你將會把那些代碼添加到靜態庫裏,而且在一個修改過的app裏使用靜態庫。最終將會獲得一個相同的app,可是會體現出面陳提到的全部優勢。

開始 Let`s Go!

打開Xcode,選擇File\New\Project,當Choose a template對話框出現時,選擇iOS\Framework & Library\Cocoa Touch Static Library,以下圖:

Choose a template

點擊Next,在項目選項對話框,輸入ImageFliters做爲項目名稱(project name),而後輸入一個惟一的公司標識(company identifier ),而且勾選Use Automatic Reference Counting,而Include Unit Tests不要勾選。

項目選項對話框

點擊Next,最後選擇一個你想要保存項目的位置,而後點擊Create

Xcode已經建立了一個準備使用靜態庫的項目,而且項目裏已經自動添加了ImageFliters類。(這難道不是Xcode的優勢麼?)這就是你將要編寫的圖像濾光代碼的地方。

注意:你能夠你想要的任何類到靜態庫裏,甚至刪除原來的代碼(ImageFliters類)。
在這個教程,全部代碼將會添加到Xcode開始自帶的類ImageFliters。

既然你項目仍然空,讓咱們添加一些代碼進去吧!

##項目:Image Filters

這個庫是爲ios設計的,而且使用了UIKit框架,因此,你要作的第一件事是:在頭文件,導入(import)UIKit框架,打開ImageFilters.h,而且在該文件最頂部添加下列代碼:

#import <UIKit/UIKit.h>

接下來,在文件@interface ImageFilters : NSObject這一行的下面,黏貼以下聲明代碼:

@property (nonatomic,readonly) UIImage *originalImage;

- (id)initWithImage:(UIImage *)image;
- (UIImage *)grayScaleImage;
- (UIImage *)oldImageWithIntensity:(CGFloat)level;

這些頭文件的聲明代碼,定義了類的公開接口。當其餘開發者(包括你本身)使用這個庫,經過讀這個頭文件,他們就知道類名和內嵌的庫中的方法。

如今,是時候添加實現代碼(implementation)了, 打開ImageFilters.m,在這行 #import "ImageFilters.h"下面黏貼以下代碼:

@interface ImageFilters()

@property (nonatomic,strong) CIContext *context; @property (nonatomic,strong) CIImage *beginImage;

@end

上面的代碼聲明瞭許多用於類內部的屬性,這些屬性並非公開的,因此任何使用這個庫的app都不能訪問這些屬性。

最後,你須要實現類中的方法,在這行@implementation ImageFilters下面黏貼以下代碼:

- (id)initWithImage:(UIImage *)image
{
    self = [super init];
    if (self) {
        _originalImage  = image;
        _context        = [CIContext contextWithOptions:nil];
    _beginImage     = [[CIImage alloc] initWithImage:_    originalImage];
    }
    return self;
}
 
- (UIImage*)imageWithCIImage:(CIImage *)ciImage
{
CGImageRef cgiImage = [self.context createCGImage:ciImage     fromRect:ciImage.extent];
    UIImage *image = [UIImage imageWithCGImage:cgiImage];
    CGImageRelease(cgiImage);
 
    return image;
}
 
- (UIImage *)grayScaleImage
{
    if( !self.originalImage)
        return nil;
 
CIImage *grayScaleFilter = [CIFilter filterWithName:@"CIColorControls" keysAndValues:kCIInputImageKey, self.beginImage, @"inputBrightness", [NSNumber numberWithFloat:0.0], @"inputContrast", [NSNumber numberWithFloat:1.1], @"inputSaturation", [NSNumber numberWithFloat:0.0], nil]    outputImage;
 
CIImage *output = [CIFilter filterWithName:@"CIExposureAdjust" keysAndValues:kCIInputImageKey, grayScaleFilter, @"inputEV",     NSNumber numberWithFloat:0.7], nil].outputImage;
 
    UIImage *filteredImage = [self imageWithCIImage:output];
    return filteredImage;
}
 
- (UIImage *)oldImageWithIntensity:(CGFloat)intensity
{
    if( !self.originalImage )
        return nil;
 
    CIFilter *sepia = [CIFilter filterWithName:@"CISepiaTone"];
    [sepia setValue:self.beginImage forKey:kCIInputImageKey];
    [sepia setValue:@(intensity) forKey:@"inputIntensity"];
 
CIFilter *random = [CIFilter filterWithName:@"CIRandomGenerator"    ;
 
    CIFilter *lighten = [CIFilter filterWithName:@"CIColorControls"];
    [lighten setValue:random.outputImage forKey:kCIInputImageKey];
    [lighten setValue:@(1 - intensity) forKey:@"inputBrightness"];
    [lighten setValue:@0.0 forKey:@"inputSaturation"];
 
CIImage *croppedImage = [lighten.outputImage    imageByCroppingToRect:[self.beginImage extent]];
 
CIFilter *composite = [CIFilter     filterWithName:@"CIHardLightBlendMode"];
    [composite setValue:sepia.outputImage forKey:kCIInputImageKey];
[composite setValue:croppedImage    forKey:kCIInputBackgroundImageKey];
 
    CIFilter *vignette = [CIFilter filterWithName:@"CIVignette"];
[vignette setValue:composite.outputImage forKey:kCIInputImageKey    ;
    [vignette setValue:@(intensity * 2) forKey:@"inputIntensity"];
    [vignette setValue:@(intensity * 30) forKey:@"inputRadius"];
 
UIImage *filteredImage = [self imageWithCIImage:vignette    outputImage];
 
    return filteredImage;
}

這上面代碼實現了初始化和執行Core Image濾光效果的方法。 由於解釋上面Core Image代碼的功能,超出本教程的範圍, 因此,您能在這個**Core Image Tutorial**教程裏,學習Core Image和濾光的相關知識。

此時,你的靜態庫擁有ImageFilters類,這個類公開以下3個方法:

  • initWithImage :初始化類
  • grayScaleImage :建立圖片的灰度效果
  • oldImageWithIntensity :建立圖片的陳舊效果

如今編譯而且運行你的庫(將Run按鈕旁邊的編譯目標改成iOS Device,這樣便於後面找到.a文件), 你將會注意到,點擊Xcode的**"Run"**按鈕,只執行編譯; 實際上,你不能經過運行你的靜態庫來看到結果,由於尚未app支持它。

靜態庫使用.a做爲擴展名,而不是.app.ipa等。 生成的靜態庫在Xcode導航欄的Products文件夾裏, 右擊 或者 「按住CTRL,單擊」 libImageFilters.a ,在彈出的菜單裏選擇Show in Finder,以下圖:

上下文菜單

Xcode將會在iFinder打開文件夾,你會看到以下:

靜態庫文件夾

一個共享庫的最終最終產品有2個部分:

  • 頭文件(Header files):在include文件夾裏,你找到靜態庫的全部公開頭文件(.h文件)。 由於你只有1個公共類,因此這個文件夾只有單獨的ImageFilters.h文件。 你在以後的app項目裏面,爲了讓Xcode在編譯時知道 輸出類(the exported classes),須要用到這個頭文件。
  • 二進制庫文件(Binary Library):Xcode生成的靜態庫文件是ImageFilters.a。當你想要在裏使用這個庫的時候,你須要使用這個文件來鏈接靜態庫。

導入新框架(framework)到app,與導入靜態庫很類似。 你只須要簡單的導入框架頭文件(framework header)和鏈接到app的框架代碼(framework code)。

靜態庫使用小警告:默認狀況下,編譯生成的庫文件僅僅適用於Xcode當前指定的架構(真機的框架爲ARM,模擬器框架爲i386)
假如你目前的編譯目標爲模擬器,庫文件將包含適用於i386架構的對象代碼;
假如你目前的編譯目標爲真機設備,庫文件將包含適用於ARM架構的對象代碼;
你須要編譯出兩個版本的靜態庫文件,當你的編譯目標在真機和模擬器間切換時,要鏈接使用對應的庫文件。

那要怎麼作才能解決上面的問題呢?

幸運的是,有一個很好的辦法, app項目不須要建立多個配置或者最終產品(build products),就能支持多個平臺。 您能夠建立一個universal binary,它包含這兩個架構的對象代碼。

##Universal Binaries(通用二進制)

通用二進制 是一種包含多個架構對象代碼的特殊二進制文件。 在Mac電腦的cpu從PowerPC (PPC) 過渡到 Intel (i386) 時,你對 通用二進制 可能會熟悉。 在過渡期間,Mac上的app一般裝載了通用二進制,通用二進制在一個二進制文件內包含了兩個平臺的可執行代碼,以便app在 Intel 和 PowerPC 架構的Mac電腦上都可運行。

支持ARM和i386架構的概念並無太多區別。既然這樣,靜態庫文件將包含適用於ios設備(ARM)和模擬器(i386)代碼。Xcode將會識別通用二進制,而且你沒戲編譯app時,Xcode會根據當前的編譯目標,選擇適當的架構。

爲了建立通用二進制庫,你須要使用一個系統工具**lipo**。

cat

不用擔憂小貓咪,lipo並非指的上圖中的脂肪(這句話屬於美式幽默,我也不太懂)。

lipo 是一種容許你在通用二進制文件進行操做(操做包括:建立通用二進制文件、顯示文件內容等等)的命令行工具。 在這個教程裏,你將會使用lipo,將不一樣架構的二進制文件 合併成 包含多個架構的內容的單獨二進制文件。 你能在命令行裏直接使用lipo,可是在這個教程裏面,你將會經過運行 一個命令行腳原本讓Xcode爲你工做,這個命令行能建立通用二進制文件。

在Xcode,一個聚合目標(An Aggregate Target)將會一次編譯多個目標(target),包括命令行腳本。 在Xcode菜單欄裏操做File/New/Target,出現以下對話框,選擇** iOS/Other**,再點擊Aggregate,以下圖

Aggregate-select

Product Name 輸入UniversalLib,確保Project欄選中ImageFilters項目,以下圖

Aggregate-create

在項目導航欄上點擊ImageFilters(以下圖操做1),而後選擇UniversalLib目標(以下圖操做2),切換到到Build Phases標籤(以下圖操做3), 這裏就是你將建立行爲的地方,當目標被編譯時,這裏的行爲將會運行。

點擊右下角Add Build Phase按鈕,在彈出菜單裏選擇Add Run Script,以下圖:

Add Run Script

如今你要建立一個腳本。展開Run Script模塊,將下面的shell代碼黏貼進去。

# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
 
# Step 1. Build Device and Simulator versions
xcodebuild -target ImageFilters ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_  ROOT="${BUILD_ROOT}"
xcodebuild -target ImageFilters -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ ROOT="${BUILD_ROOT}"
 
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
 
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a"     "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
 
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_    OUTPUTFOLDER}/"

上面的代碼並不複雜,下面將逐行解釋代碼如何運行:

  • UNIVERSAL_OUTPUTFOLDER :通用二進制文件「Debug-universal」將被拷貝到的目標文件夾的路徑名稱。
  • Step 1 代碼的第二行,你將調用xcodebuild,而且指導它編譯ARM架構二進制文件(你將會在這行看到參數**-sdk iphoneos**)。
  • 下一行代碼再次調用xcodebuild,而且在另外一個文件夾爲iPhone模擬器編譯生成i386架構二進制文件,但此次的參數爲**-sdk iphonesimulator -arch i386**。 (假如你對此很感興趣,你您能在**man page學習更多xcodebuild**的相關知識)
  • Step 2 如今你已經擁有分別針對兩種架構的兩個.a靜態庫文件,你只要調用 lipo -create 而且設置它建立、輸出一個通用二進制文件。
  • 在最後一行,你將頭文件拷貝到 用於生成通用二進制的文件夾內(使用cpshell命令行)。

你的「Run Script 」窗口應該以下圖同樣:

Run Script

如今你要準備去編譯通用版本的靜態庫。在策略選擇下拉表,選擇聚合目標UniversalLib,以下圖(你的Xcode有一點可能和下圖不一樣,下圖中的「IOS Device」,在你的Xcode可能顯示爲你真實的設備名稱)。

聚合UniversalLib

點擊Run按鈕,編譯聚合策略(aggregate scheme)裏選擇的目標。

爲了看到結果,對項目導航欄裏的Product文件夾下的libImageFilters.a右擊,選擇Show in Finder*, 爲了能看到文件夾的上下層次,切換Finder裏顯示文件夾的樣式爲列表樣式,你將會看到一個新文件夾Debug-Universal(若是你在編譯Release版本,文件夾名可能會是Release-Universal),這個文件夾包含通用版本(Universal)靜態庫,以下圖:

Debug-Universal

你會發現,除了模擬器和設備文件夾,通用靜態庫文件和頭文件都出現了。(這行翻譯可能有誤,原文以下)。

You’ll find the usual headers and static library files are present, except this one links with both the simulator and the device.

以上,就是你爲了建立本身的靜態庫而須要學習的東西。

簡單來講,一個靜態庫項目和一個app項目很類似。你能夠有一個或多個類,最終編譯出來的產品是頭文件個一個裝有代碼的.a文件,這個.a文件就是能被鏈接到多個app裏的靜態庫。

##在本身的App裏使用靜態庫

在本身的App裏使用ImageFilters類與直接從源碼使用 差很少:導入頭文件而且開始使用類。 (這行翻譯可能不太準確,原文以下)

Using the ImageFilters class in your own app is not very different from using it directly from source: you import the header file and start using the class!

問題是,Xcode並不知道頭文件或者二進制文件的位置。

把靜態庫放進項目裏,這有兩個方法:

  • 方法1: 直接引用頭文件和庫的二進制文件(.a文件)。
  • 方法2: 在你本身的項目裏導入靜態庫項目,把靜態庫做爲你項目的子項目。

選擇其中一個方法或者其餘方法,依賴於你本身的選擇: 在你的項目中,是否須要靜態庫的源碼和項目文件。

在這個教程裏,這兩個方法都在下面單獨詳細描述了。你能夠嘗試其中的一個方法,可是最好按照下面描述的順序,把兩個方法都瞭解一下。 在兩個方法的開始部分,你將被要求下載一個zip文件,這個文件是教程**Core Image Tutorial裏的app的一個修改版本。(修改:使用了來自於靜態庫的新類ImageFilters**)。

既然這個教程的目標是叫你怎樣使用靜態庫,這個修改版本包含全部app須要的源碼。 這樣,你就能專一於項目使用靜態庫的配置。

##方法1:引用頭文件和庫的二進制文件(.a文件)

對於這部分教程,你須要下載 starter project for this section。 拷貝下載好的zip文件到磁盤的任意一個文件夾下,解壓zip。你將看到以下的文件夾結構:

方法1,zip文件夾結構

爲了讓你方便,靜態庫頭文件和.a文件的副本已經被包含在項目中,你就不用再次拷貝了, 可是項目並無配置好來使用靜態庫,這就是你要作的

  • 注意:經典Unix慣例,引用外部包,
  • 引用的文件夾裏面有一個包含頭文件的文件夾「include」,
  • 還有一個包含.a文件的文件夾 「lib」。
  • 這個文件夾結構僅僅是一個慣例,不是強制性的。
  • 在你的項目裏引用靜態庫時,你並不須要遵循這個文件結構。在你本身的app裏,你能夠把頭文件和庫文件放在項目的任意位置,接下來,只要在你配置Xcode的時候,設置合理的目錄路徑就行。(這個目錄路徑必須可以讓Xcode找到所需的.a文件和頭文件)。

打開項目,編譯、運行你的app,你將會看到以下編譯錯誤提示:

編譯error-1

如我所料,app沒法找到頭文件。 爲了解決這個問題,你須要在項目裏增長頭文件搜索路徑(Header Search Path),來指出頭文件所在文件夾的位置。使用靜態庫的時候,老是首先配置頭文件搜索路徑(Header Search Path)

以下圖所示,按照圖示的1~4的步驟操做,在第3步點擊了Build Settings標籤後,在搜索欄輸入關鍵字**「header search」**,以便快速定位到咱們配置的那行參數。

header search

雙擊Header Search Paths這行的後半空白部分,將會彈出下圖界面,點擊下圖左下角的「+」按鈕,而後輸入一下信息:
$SOURCE_ROOT/include

header search - pop

$SOURCE_ROOT是Xcode的環境參數,指的是項目的根文件夾(the project’s root folder), Xcode將會使用包含該項目的真實文件夾的路徑地址來代替此參數,這樣,即便你把整個項目移動到別的文件夾或者移動到別的電腦上,你也不用再更改路徑參數了,由於Xcode利用此參數來幫你解決了這些麻煩的問題。

點擊上圖彈出框的外圍部分來關閉彈出框,你將會看到,Xcode已經把參數「$SOURCE_ROOT」轉換爲項目所在文件夾的真實路徑地址,以下圖:

SOURCE_ROOT-true

再次編譯運行你的app,你會發現還會存在error,以下所示:

build-error-2

看起來狀況不太好,可是Xcode也給出了部分提示信息。若是你仔細看看error信息,上面編譯出現的「編譯error信息」已經消失,取而代之,如今的error信息是鏈接錯誤(linker errors)。 這就說明,Xcode已經找到頭文件而且用它來編譯app,可是程序鏈接階段,Xcode找不到ImageFliter類對象代碼。 爲何呢?

這很簡單,你還沒告訴Xcode在哪裏你呢個找到包含類實現代碼的庫文件(.a文件)。 (看樣子,這也不是什麼太糟糕的問題)

以下圖所示,按照1~5的步驟操做,

  • 1:點擊項目文件
  • 2:選擇CoreImageFun目標
  • 3:切換到Build Phases 標籤
  • 4:點擊Link Binary With Libraries部分最左邊的小箭頭,展開該部分
  • 5:點擊該部分左下角的「+」按鈕,彈出「添加庫」界面

add binary library

下圖爲「添加庫」界面,點擊左下角的Add Other…按鈕,定位到該項目文件夾裏的lib文件夾,找到libImageFilters.a庫文件,添加進去。

add libImageFilters.a

當你作完以上步驟,下圖就應該是你XcodeBuild Phases標籤界面的樣子(注意,libImageFilters.a已經被添加進去了。)

after add libImageFilters.a

最後一步,在Xcode裏添加**-ObjC**編譯標識, 這個標識有時能夠排除部分靜態庫代碼,只把有效的代碼導入項目。(見下段註解)

-ObjC編譯標識: (此段爲譯者注)

例如,你的項目使用了第三方開源類JSONKit,而你的靜態庫也用到了這個JSONKit,那麼你把靜態庫導入到項目後,這就產生衝突,因此你在把靜態庫導入項目時,靜態庫裏的JSONKit.h頭文件就沒必要導入,由於你的項目裏已經有了JSONKit.h,JSONKit.m文件,使用**-ObjC**編譯標識,Xcode就會變得聰明,Xcode知道你的項目裏已經有了JSONKit的實現代碼,即JSONKit.m文件,因此,靜態庫的JSONKit.m文件就不會被導入,這樣,你的項目和靜態庫就共用你項目裏面的JSONKit.m文件。你能夠作一個相關實驗嘗試一下,把項目和靜態庫裏的JSONKit.m文件裏的內容寫的不同,看看,最終app裏到底使用的哪一個文件。

-ObjC編譯標識功能不少,使用這個標識,可讓靜態庫裏的類和類別(categories)文件被合理的加載進來。 你能夠在**Technical Q&A QA1490學習更多-ObjC**編譯標識相關知識。

添加**-ObjC編譯標識的方法以下圖,點擊Build Settings標籤,在右上角的搜索框輸入Other linker** 便可搜索到。

 Other linker Flags-search

Other linker Flags(不用展開該行)這行的後半空白部分雙擊,彈出下圖界面,點擊彈出框左下角的「+」按鈕,輸入-ObjC便可

 Other linker Flags-add -ObjC

最後,編譯、運行你的app;你不會再看到任何編譯error,編譯成功,app將會運行起來,以下圖:

run success

你能夠嘗試點擊app上的按鈕和滑動條,看看具體效果。 執行這些圖片變化效果的代碼並不在app,而是在靜態庫。

恭喜你!你剛剛在一個真實的app裏編譯、運行了你的第一個靜態庫。 包含頭文件和靜態庫文件的方法,已經被用在不少知名的第三方庫裏, 例如AdMob, TestFlight或者那些不想提供源代碼的商業庫(百度地圖、微博分享等等)。

##方法2:將靜態庫做爲子項目加載

對於這部分教程,你須要下載裏一個文件, 點此下載

將下載好的zip文件拷貝你但願的位置,解壓zip,你會看到以下圖的文件結構

method2-zip

若是你看了上面的方法1,你會注意到,此次解壓後的項目文件夾的根目錄和方法1的不一樣: 這個項目文件夾根目錄,沒有任何頭文件和.a文件(由於方法2不須要這些東西)。 取而代之,你將會看到,在本教程開始部分建立的ImageFilters靜態庫項目 做爲子項目被添加到這個項目裏。

在你作其它事情以前,你先編譯、運行這個app,你將會被下圖的error問候:

method2-error-1

若是你看過本教程的方法1,你可能已經知道該如何修復這個error。 在你剛剛下載解壓的項目裏,你在ViewController類裏使用了ImageFilters類 ,但你仍然沒有告訴Xcode頭文件在哪裏。你運行該項目時,Xcode找不到ImageFilters.h文件,因此編譯失敗。

爲了把ImageFilters靜態庫項目導入進來做爲子項目,有2個方法:

  • 導入方法1:打開ImageFilters項目,你只須要從靜態庫項目窗口 拖曳 靜態庫項目的項目文件(通常爲ImageFilters項目導航欄的最上面的那個文件) 到主項目(這裏是CoreImageFun項目)窗口的導航欄中的任何地方便可,由於目前ImageFilters項目已經在窗口中打開,因此在主項目窗口裏顯示的ImageFilters文件只是單個文件,而不是樹狀結構。你要關閉這兩個項目,而後再打開主項目CoreImageFun,你就會發現它已經變爲樹狀結構。以下圖
  • 導入方法2:先關閉ImageFilters項目,而後在文件夾中,找到靜態庫的項目文件(即ImageFilters.xcodeproj文件),拖曳該文件到主項目CoreImageFun的導航欄中便可。以下圖

add-subProject

注意:這兩個方法的最終效果是同樣的(以下圖),在執行上面的方法2,儘可能確保子項目(這裏指的是ImageFilters靜態庫項目)並無在Xcode中打開,
不然的話,你須要關閉這兩個項目,再從新打開主項目。由於同一個項目,不能同時在兩個窗口中打開。

after add-subProject

如今Xcode知道了靜態庫子項目,你能夠把添加靜態庫到項目依賴(Dependencies),以下圖操做。 這就意味着,Xcode將確保在編譯app前,靜態庫的代碼是最新的(就是說,若是靜態庫項目有代碼變動,主項目會自動從新編譯靜態庫項目)。

Xcode添加項目依賴,以下圖操做1~4,

add-Dependencies

點擊上圖步驟4的「+」號按鈕會彈出另外一個窗口,彈出的窗口以下圖,在下拉列表裏選擇ImageFilters目標(而不是universalLib),點擊右下角的「add」,完成。

add-Dependencies-pop

完成上面的添加依賴的步驟後,Build Phases標籤的Target Dependencies部分,將會增長一條,以下圖:

after-add-Dependencies

最後一步,配置項目,將靜態庫鏈接到項目。以下圖,展開Link Binary with libraries部分.

Link Binary with libraries

點擊上圖的「+」號按鈕,彈出 下圖的界面, 選擇libImageFilters.a項目,點擊add

method2-add static lib

添加完成後,Link Binary with Libraries部分以下圖所示:

after-method2-add static lib

最後一步,添加**-ObjC**編譯標識,添加步驟與上面的方法1的最後一步同樣,以下圖:

method2 add ObjC

在上圖Other linker Flags行的後半空白部分雙擊,彈出以下圖, 點擊彈出框左下角「+」按鈕,添加 -ObjC

after method2 add ObjC

編譯運行你的app,app將會運行成功,以下圖:

method2 success

你能夠操做一下剛剛運行成功的app。
與方法1同樣,圖片效果的邏輯代碼,都在靜態庫中。

若是你按照方法1試驗過添加靜態庫的過程(使用頭文件和靜態庫),在處理方式上,和方法2有不少不一樣之處。 在方法2,你沒有爲Xcode配置header search paths參數。
另外一個不一樣之處,你沒有使用過通用靜態庫(Universal library)。

爲何會不一樣?
把靜態庫項目添加爲子項目,Xcode就幾乎爲你解決了全部事情。
添加子項目和依賴以後,Xcode就知道了在哪裏找到頭文件和靜態庫文件, 並且靜態庫的架構會根據你app選擇的參數來編譯,這真是夠方便的。

若是你使用本身的靜態庫,或者你須要訪問源碼和項目文件, 那麼,導入靜態庫到項目較爲方便的方法:方法2(即添加靜態庫項目做爲子項目); 由於你集成子項目做爲項目依賴,你須要操做、擔憂的事情就不多了,歐耶!

#資源文件打包(這部分爲譯者添加)

在靜態庫裏常常會遇到 圖片xib各類外部文件等等,這些不能放在靜態庫裏, 一般的作法是:把這些文件打成一個bundle包(擴展名爲.bundle的文件)。
打bundle包,也能夠建一個target,就像合併兩種架構靜態庫的target的作法差很少。 具體作法點此

#接下來去哪裏?

你能夠在**這裏**下載這個教程的全部項目代碼。

對於靜態庫的基本概念、怎樣在本身的app使用靜態庫,但願這個教程會對你有所幫助。

接下來,用上面的知識去編譯你本身的靜態庫! 你確定有須要添加到全部項目裏的通用類,把這些代碼放在你本身的靜態庫裏重用會是個很好的注意。 你還可以根據功能分類,建立多個靜態庫: 一個靜態庫放網絡交互的代碼, 一個放UI相關類的代碼,等等。 這樣你就能把你須要的模塊添加到項目裏。

爲了進一步鞏固、更深一步學習本教程的內容, 我也推薦你看看蘋果官方文檔裏有關靜態庫的內容 Introduction to Using Static Libraries in iOS

但願你能喜歡這個教程,若是你有任何問題和想法,請加入論壇討論。


#####如下爲譯者注

這篇文章使用Markdown語言編寫,使用了以下工具:

本人英語也不是太好,翻譯質量不是過高,若有不妥之處,歡迎在下面留言,指點批評。

相關文章
相關標籤/搜索