午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

【翻譯】ios教程

 爽行天下丶 2015-06-16

作者:shede333
主頁(yè):http://my.oschina.net/shede333
版權(quán)聲明:原創(chuàng)文章,版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名 | [Creative Commons BY-NC-ND 3.0][]


本人英語(yǔ)也不是太好,翻譯質(zhì)量不是太高,如有不妥之處,歡迎指點(diǎn)批評(píng)。

點(diǎn)此查看文章 英文原文

創(chuàng)建IOS靜態(tài)庫(kù)

如果你開發(fā)ios有一段時(shí)間了,你可能有許多想在你大部分項(xiàng)目里重用的類和工具函數(shù)。

重用代碼最容易的方法就是復(fù)制/黏貼,但是,這在代碼維護(hù)上很快就變成一個(gè)噩夢(mèng)。
既然每一個(gè)app都擁有一份 共享代碼 的拷貝,這就很難保證所有 拷貝的代碼共享代碼 在bug修正與更新的同步(一致性)。

這里就使用靜態(tài)庫(kù)來(lái)拯救噩夢(mèng)。靜態(tài)庫(kù)就是類、函數(shù)、定義(definitions)和資源的一個(gè)包,使用靜態(tài)庫(kù),你能把代碼打包在一起,并且在你所有的項(xiàng)目間共享。

在這個(gè)教程,你將親身經(jīng)歷使用兩種不同的方法創(chuàng)建你自己的通用靜態(tài)庫(kù)。

你應(yīng)該熟悉Objective-C and iOS開發(fā),才能理解大致上這個(gè)教程。
如果你對(duì)怎樣做一個(gè)相同的app 以及 圖像濾光代碼在庫(kù)里的工作原理 感興趣,Core Image的相關(guān)知識(shí)雖然不是必須的,但是對(duì)你會(huì)很有幫助。

準(zhǔn)備開始高效的減少、重用和循環(huán)使用你的代碼吧!

為什么使用靜態(tài)庫(kù)

你可能因?yàn)楹芏嘣蚨鴦?chuàng)建靜態(tài)庫(kù):

  • 你想要把你或者你團(tuán)隊(duì)里的成員編寫的類打包在一起,便于合理的使用,并且很容易與周圍的人分享。
  • 你想要讓所有通用的代碼集中到一起,便于你對(duì)代碼的bug修復(fù)與更新。
  • 你想和一些人分享你的代碼庫(kù),但是你不想要他們看到你的代碼。
  • 隨著開發(fā)時(shí)間的進(jìn)展,你想要做一個(gè)版本庫(kù)的快照。

在這個(gè)教程里,假設(shè)你已經(jīng)看過(guò)Core Image Tutorial這個(gè)教程,并且理解了如何使用一些照片處理效果的代碼。

你將會(huì)把那些代碼添加到靜態(tài)庫(kù)里,并且在一個(gè)修改過(guò)的app里使用靜態(tài)庫(kù)。最終將會(huì)得到一個(gè)相同的app,但是會(huì)體現(xiàn)出面陳提到的所有優(yōu)點(diǎn)。

開始 Let`s Go!

打開Xcode,選擇File\New\Project,當(dāng)Choose a template對(duì)話框出現(xiàn)時(shí),選擇iOS\Framework & Library\Cocoa Touch Static Library,如下圖:

Choose a template

點(diǎn)擊Next,在項(xiàng)目選項(xiàng)對(duì)話框,輸入ImageFliters作為項(xiàng)目名稱(project name),然后輸入一個(gè)唯一的公司標(biāo)識(shí)(company identifier ),并且勾選Use Automatic Reference Counting,而Include Unit Tests不要勾選。

項(xiàng)目選項(xiàng)對(duì)話框

點(diǎn)擊Next,最后選擇一個(gè)你想要保存項(xiàng)目的位置,然后點(diǎn)擊Create。

Xcode已經(jīng)創(chuàng)建了一個(gè)準(zhǔn)備使用靜態(tài)庫(kù)的項(xiàng)目,并且項(xiàng)目里已經(jīng)自動(dòng)添加了ImageFliters類。(這難道不是Xcode的優(yōu)點(diǎn)么?)這就是你將要編寫的圖像濾光代碼的地方。

注意:你可以你想要的任何類到靜態(tài)庫(kù)里,甚至刪除原來(lái)的代碼(ImageFliters類)。
在這個(gè)教程,所有代碼將會(huì)添加到Xcode開始自帶的類ImageFliters。

既然你項(xiàng)目仍然空,讓我們添加一些代碼進(jìn)去吧!

項(xiàng)目:Image Filters

這個(gè)庫(kù)是為ios設(shè)計(jì)的,并且使用了UIKit框架,所以,你要做的第一件事是:在頭文件,導(dǎo)入(import)UIKit框架,打開ImageFilters.h,并且在該文件最頂部添加下列代碼:

#import <UIKit/UIKit.h>

接下來(lái),在文件@interface ImageFilters : NSObject這一行的下面,黏貼如下聲明代碼:

@property (nonatomic,readonly) UIImage *originalImage;

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

這些頭文件的聲明代碼,定義了類的公開接口。當(dāng)其他開發(fā)者(包括你自己)使用這個(gè)庫(kù),通過(guò)讀這個(gè)頭文件,他們就知道類名和內(nèi)嵌的庫(kù)中的方法。

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

@interface ImageFilters()

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

@end

上面的代碼聲明了許多用于類內(nèi)部的屬性,這些屬性并不是公開的,所以任何使用這個(gè)庫(kù)的app都不能訪問(wèn)這些屬性。

最后,你需要實(shí)現(xiàn)類中的方法,在這行@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;
}

這上面代碼實(shí)現(xiàn)了初始化和執(zhí)行Core Image濾光效果的方法。
因?yàn)榻忉屔厦?code>Core Image代碼的功能,超出本教程的范圍,
所以,您能在這個(gè)Core Image Tutorial教程里,學(xué)習(xí)Core Image和濾光的相關(guān)知識(shí)。

此時(shí),你的靜態(tài)庫(kù)擁有ImageFilters類,這個(gè)類公開如下3個(gè)方法:

  • initWithImage :初始化類
  • grayScaleImage :創(chuàng)建圖片的灰度效果
  • oldImageWithIntensity :創(chuàng)建圖片的陳舊效果

現(xiàn)在編譯并且運(yùn)行你的庫(kù)(將Run按鈕旁邊的編譯目標(biāo)改為iOS Device,這樣便于后面找到.a文件),
你將會(huì)注意到,點(diǎn)擊Xcode的“Run”按鈕,只執(zhí)行編譯;
實(shí)際上,你不能通過(guò)運(yùn)行你的靜態(tài)庫(kù)來(lái)看到結(jié)果,因?yàn)檫€沒有app支持它。

靜態(tài)庫(kù)使用.a作為擴(kuò)展名,而不是.app.ipa等。
生成的靜態(tài)庫(kù)在Xcode導(dǎo)航欄的Products文件夾里,
右擊 或者 “按住CTRL,單擊” libImageFilters.a ,在彈出的菜單里選擇Show in Finder,如下圖:

上下文菜單

Xcode將會(huì)在iFinder打開文件夾,你會(huì)看到如下:

靜態(tài)庫(kù)文件夾

一個(gè)共享庫(kù)的最終最終產(chǎn)品有2個(gè)部分:

  • 頭文件(Header files):在include文件夾里,你找到靜態(tài)庫(kù)的所有公開頭文件(.h文件)。
    因?yàn)槟阒挥?個(gè)公共類,所以這個(gè)文件夾只有單獨(dú)的ImageFilters.h文件。
    你在之后的app項(xiàng)目里面,為了讓Xcode在編譯時(shí)知道 輸出類(the exported classes),需要用到這個(gè)頭文件。
  • 二進(jìn)制庫(kù)文件(Binary Library):Xcode生成的靜態(tài)庫(kù)文件是ImageFilters.a。當(dāng)你想要在里使用這個(gè)庫(kù)的時(shí)候,你需要使用這個(gè)文件來(lái)連接靜態(tài)庫(kù)。

導(dǎo)入新框架(framework)到app,與導(dǎo)入靜態(tài)庫(kù)很相似。
你只需要簡(jiǎn)單的導(dǎo)入框架頭文件(framework header)和連接到app的框架代碼(framework code)。

靜態(tài)庫(kù)使用小警告:默認(rèn)情況下,編譯生成的庫(kù)文件僅僅適用于Xcode當(dāng)前指定的架構(gòu)(真機(jī)的框架為ARM,模擬器框架為i386)
假如你目前的編譯目標(biāo)為模擬器,庫(kù)文件將包含適用于i386架構(gòu)的對(duì)象代碼;
假如你目前的編譯目標(biāo)為真機(jī)設(shè)備,庫(kù)文件將包含適用于ARM架構(gòu)的對(duì)象代碼;
你需要編譯出兩個(gè)版本的靜態(tài)庫(kù)文件,當(dāng)你的編譯目標(biāo)在真機(jī)和模擬器間切換時(shí),要連接使用對(duì)應(yīng)的庫(kù)文件。

那要怎么做才能解決上面的問(wèn)題呢?

幸運(yùn)的是,有一個(gè)很好的辦法,
app項(xiàng)目不需要?jiǎng)?chuàng)建多個(gè)配置或者最終產(chǎn)品(build products),就能支持多個(gè)平臺(tái)。
您可以創(chuàng)建一個(gè)universal binary,它包含這兩個(gè)架構(gòu)的對(duì)象代碼。

Universal Binaries(通用二進(jìn)制)

通用二進(jìn)制 是一種包含多個(gè)架構(gòu)對(duì)象代碼的特殊二進(jìn)制文件。
在Mac電腦的cpu從PowerPC (PPC) 過(guò)渡到 Intel (i386) 時(shí),你對(duì) 通用二進(jìn)制 可能會(huì)熟悉。
在過(guò)渡期間,Mac上的app通常裝載了通用二進(jìn)制,通用二進(jìn)制在一個(gè)二進(jìn)制文件內(nèi)包含了兩個(gè)平臺(tái)的可執(zhí)行代碼,以便app在 Intel 和 PowerPC 架構(gòu)的Mac電腦上均可運(yùn)行。

支持ARM和i386架構(gòu)的概念并沒有太多區(qū)別。既然這樣,靜態(tài)庫(kù)文件將包含適用于ios設(shè)備(ARM)和模擬器(i386)代碼。Xcode將會(huì)識(shí)別通用二進(jìn)制,并且你沒戲編譯app時(shí),Xcode會(huì)根據(jù)當(dāng)前的編譯目標(biāo),選擇適當(dāng)?shù)募軜?gòu)。

為了創(chuàng)建通用二進(jìn)制庫(kù),你需要使用一個(gè)系統(tǒng)工具lipo。

cat

不用擔(dān)心小貓咪,lipo并不是指的上圖中的脂肪(這句話屬于美式幽默,我也不太懂)。

lipo 是一種允許你在通用二進(jìn)制文件進(jìn)行操作(操作包括:創(chuàng)建通用二進(jìn)制文件、顯示文件內(nèi)容等等)的命令行工具。
在這個(gè)教程里,你將會(huì)使用lipo,將不同架構(gòu)的二進(jìn)制文件 合并成 包含多個(gè)架構(gòu)的內(nèi)容的單獨(dú)二進(jìn)制文件。
你能在命令行里直接使用lipo,但是在這個(gè)教程里面,你將會(huì)通過(guò)運(yùn)行 一個(gè)命令行腳本來(lái)讓Xcode為你工作,這個(gè)命令行能創(chuàng)建通用二進(jìn)制文件。

在Xcode,一個(gè)聚合目標(biāo)(An Aggregate Target)將會(huì)一次編譯多個(gè)目標(biāo)(target),包括命令行腳本。
在Xcode菜單欄里操作File/New/Target,出現(xiàn)如下對(duì)話框,選擇 iOS/Other,再點(diǎn)擊Aggregate,如下圖

Aggregate-select

Product Name 輸入UniversalLib,確保Project欄選中ImageFilters項(xiàng)目,如下圖

Aggregate-create

在項(xiàng)目導(dǎo)航欄上點(diǎn)擊ImageFilters(如下圖操作1),然后選擇UniversalLib目標(biāo)(如下圖操作2),切換到到Build Phases標(biāo)簽(如下圖操作3),
這里就是你將創(chuàng)建行為的地方,當(dāng)目標(biāo)被編譯時(shí),這里的行為將會(huì)運(yùn)行。

點(diǎn)擊右下角Add Build Phase按鈕,在彈出菜單里選擇Add Run Script,如下圖:

Add Run Script

現(xiàn)在你要?jiǎng)?chuàng)建一個(gè)腳本。展開Run Script模塊,將下面的shell代碼黏貼進(jìn)去。

# 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}/"

上面的代碼并不復(fù)雜,下面將逐行解釋代碼如何運(yùn)行:

  • UNIVERSAL_OUTPUTFOLDER :通用二進(jìn)制文件“Debug-universal”將被拷貝到的目標(biāo)文件夾的路徑名稱。
  • Step 1 代碼的第二行,你將調(diào)用xcodebuild,并且指導(dǎo)它編譯ARM架構(gòu)二進(jìn)制文件(你將會(huì)在這行看到參數(shù)-sdk iphoneos)。
  • 下一行代碼再次調(diào)用xcodebuild,并且在另一個(gè)文件夾為iPhone模擬器編譯生成i386架構(gòu)二進(jìn)制文件,但這次的參數(shù)為-sdk iphonesimulator -arch i386。
    (假如你對(duì)此很感興趣,你您能在man page學(xué)習(xí)更多xcodebuild的相關(guān)知識(shí))
  • Step 2 現(xiàn)在你已經(jīng)擁有分別針對(duì)兩種架構(gòu)的兩個(gè).a靜態(tài)庫(kù)文件,你只要調(diào)用 lipo -create 并且設(shè)置它創(chuàng)建、輸出一個(gè)通用二進(jìn)制文件。
  • 在最后一行,你將頭文件拷貝到 用于生成通用二進(jìn)制的文件夾內(nèi)(使用cpshell命令行)。

你的“Run Script ”窗口應(yīng)該如下圖一樣:

Run Script

現(xiàn)在你要準(zhǔn)備去編譯通用版本的靜態(tài)庫(kù)。在策略選擇下拉表,選擇聚合目標(biāo)UniversalLib,如下圖(你的Xcode有一點(diǎn)可能和下圖不同,下圖中的“IOS Device”,在你的Xcode可能顯示為你真實(shí)的設(shè)備名稱)。

聚合UniversalLib

點(diǎn)擊Run按鈕,編譯聚合策略(aggregate scheme)里選擇的目標(biāo)。

為了看到結(jié)果,對(duì)項(xiàng)目導(dǎo)航欄里的Product文件夾下的libImageFilters.a右擊,選擇Show in Finder,
為了能看到文件夾的上下層次,切換Finder里顯示文件夾的樣式為列表樣式,你將會(huì)看到一個(gè)新文件夾
Debug-Universal(如果你在編譯Release版本,文件夾名可能會(huì)是Release-Universal*),這個(gè)文件夾包含通用版本(Universal)靜態(tài)庫(kù),如下圖:

Debug-Universal

你會(huì)發(fā)現(xiàn),除了模擬器和設(shè)備文件夾,通用靜態(tài)庫(kù)文件和頭文件都出現(xiàn)了。(這行翻譯可能有誤,原文如下)。

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

以上,就是你為了創(chuàng)建自己的靜態(tài)庫(kù)而需要學(xué)習(xí)的東西。

簡(jiǎn)單來(lái)說(shuō),一個(gè)靜態(tài)庫(kù)項(xiàng)目和一個(gè)app項(xiàng)目很相似。你可以有一個(gè)或多個(gè)類,最終編譯出來(lái)的產(chǎn)品是頭文件個(gè)一個(gè)裝有代碼的.a文件,這個(gè).a文件就是能被連接到多個(gè)app里的靜態(tài)庫(kù)。

在自己的App里使用靜態(tài)庫(kù)

在自己的App里使用ImageFilters類與直接從源碼使用 差不多:導(dǎo)入頭文件并且開始使用類。
(這行翻譯可能不太準(zhǔn)確,原文如下)

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!

問(wèn)題是,Xcode并不知道頭文件或者二進(jìn)制文件的位置。

把靜態(tài)庫(kù)放進(jìn)項(xiàng)目里,這有兩個(gè)方法:

  • 方法1: 直接引用頭文件和庫(kù)的二進(jìn)制文件(.a文件)。
  • 方法2: 在你自己的項(xiàng)目里導(dǎo)入靜態(tài)庫(kù)項(xiàng)目,把靜態(tài)庫(kù)作為你項(xiàng)目的子項(xiàng)目。

選擇其中一個(gè)方法或者其他方法,依賴于你自己的選擇:
在你的項(xiàng)目中,是否需要靜態(tài)庫(kù)的源碼和項(xiàng)目文件。

在這個(gè)教程里,這兩個(gè)方法都在下面單獨(dú)詳細(xì)描述了。你可以嘗試其中的一個(gè)方法,但是最好按照下面描述的順序,把兩個(gè)方法都了解一下。
在兩個(gè)方法的開始部分,你將被要求下載一個(gè)zip文件,這個(gè)文件是教程Core Image Tutorial里的app的一個(gè)修改版本。(修改:使用了來(lái)自于靜態(tài)庫(kù)的新類ImageFilters)。

既然這個(gè)教程的目標(biāo)是叫你怎樣使用靜態(tài)庫(kù),這個(gè)修改版本包含所有app需要的源碼。
這樣,你就能專注于項(xiàng)目使用靜態(tài)庫(kù)的配置。

方法1:引用頭文件和庫(kù)的二進(jìn)制文件(.a文件)

對(duì)于這部分教程,你需要下載 starter project for this section。
拷貝下載好的zip文件到磁盤的任意一個(gè)文件夾下,解壓zip。你將看到如下的文件夾結(jié)構(gòu):

方法1,zip文件夾結(jié)構(gòu)

為了讓你方便,靜態(tài)庫(kù)頭文件和.a文件的副本已經(jīng)被包含在項(xiàng)目中,你就不用再次拷貝了,
但是項(xiàng)目并沒有配置好來(lái)使用靜態(tài)庫(kù),這就是你要做的

  • 注意:經(jīng)典Unix慣例,引用外部包,
  • 引用的文件夾里面有一個(gè)包含頭文件的文件夾“include”,
  • 還有一個(gè)包含.a文件的文件夾 “l(fā)ib”。
  • 這個(gè)文件夾結(jié)構(gòu)僅僅是一個(gè)慣例,不是強(qiáng)制性的。
  • 在你的項(xiàng)目里引用靜態(tài)庫(kù)時(shí),你并不需要遵循這個(gè)文件結(jié)構(gòu)。在你自己的app里,你可以把頭文件和庫(kù)文件放在項(xiàng)目的任意位置,接下來(lái),只要在你配置Xcode的時(shí)候,設(shè)置合理的目錄路徑就行。(這個(gè)目錄路徑必須能夠讓Xcode找到所需的.a文件和頭文件)。

打開項(xiàng)目,編譯、運(yùn)行你的app,你將會(huì)看到如下編譯錯(cuò)誤提示:

編譯error-1

如我所料,app無(wú)法找到頭文件。
為了解決這個(gè)問(wèn)題,你需要在項(xiàng)目里增加頭文件搜索路徑(Header Search Path),來(lái)指出頭文件所在文件夾的位置。使用靜態(tài)庫(kù)的時(shí)候,總是首先配置頭文件搜索路徑(Header Search Path)

如下圖所示,按照?qǐng)D示的1~4的步驟操作,在第3步點(diǎn)擊了Build Settings標(biāo)簽后,在搜索欄輸入關(guān)鍵字“header search”,以便快速定位到我們配置的那行參數(shù)。

header search

雙擊Header Search Paths這行的后半空白部分,將會(huì)彈出下圖界面,點(diǎn)擊下圖左下角的“+”按鈕,然后輸入一下信息:
$SOURCE_ROOT/include

header search - pop

$SOURCE_ROOT是Xcode的環(huán)境參數(shù),指的是項(xiàng)目的根文件夾(the project’s root folder),
Xcode將會(huì)使用包含該項(xiàng)目的真實(shí)文件夾的路徑地址來(lái)代替此參數(shù),這樣,即使你把整個(gè)項(xiàng)目移動(dòng)到別的文件夾或者移動(dòng)到別的電腦上,你也不用再更改路徑參數(shù)了,因?yàn)閄code利用此參數(shù)來(lái)幫你解決了這些麻煩的問(wèn)題。

點(diǎn)擊上圖彈出框的外圍部分來(lái)關(guān)閉彈出框,你將會(huì)看到,Xcode已經(jīng)把參數(shù)“$SOURCE_ROOT”轉(zhuǎn)換為項(xiàng)目所在文件夾的真實(shí)路徑地址,如下圖:

SOURCE_ROOT-true

再次編譯運(yùn)行你的app,你會(huì)發(fā)現(xiàn)還會(huì)存在error,如下所示:

build-error-2

看起來(lái)情況不太好,但是Xcode也給出了部分提示信息。如果你仔細(xì)看看error信息,上面編譯出現(xiàn)的“編譯error信息”已經(jīng)消失,取而代之,現(xiàn)在的error信息是連接錯(cuò)誤(linker errors)。
這就說(shuō)明,Xcode已經(jīng)找到頭文件并且用它來(lái)編譯app,但是程序連接階段,Xcode找不到ImageFliter類對(duì)象代碼。
為什么呢?

這很簡(jiǎn)單,你還沒告訴Xcode在哪里你呢個(gè)找到包含類實(shí)現(xiàn)代碼的庫(kù)文件(.a文件)。
(看樣子,這也不是什么太糟糕的問(wèn)題)

如下圖所示,按照1~5的步驟操作,

  • 1:點(diǎn)擊項(xiàng)目文件
  • 2:選擇CoreImageFun目標(biāo)
  • 3:切換到Build Phases 標(biāo)簽
  • 4:點(diǎn)擊Link Binary With Libraries部分最左邊的小箭頭,展開該部分
  • 5:點(diǎn)擊該部分左下角的“+”按鈕,彈出“添加庫(kù)”界面

add binary library

下圖為“添加庫(kù)”界面,點(diǎn)擊左下角的Add Other…按鈕,定位到該項(xiàng)目文件夾里的lib文件夾,找到libImageFilters.a庫(kù)文件,添加進(jìn)去。

add libImageFilters.a

當(dāng)你做完以上步驟,下圖就應(yīng)該是你XcodeBuild Phases標(biāo)簽界面的樣子(注意,libImageFilters.a已經(jīng)被添加進(jìn)去了。)

after add libImageFilters.a

最后一步,在Xcode里添加-ObjC編譯標(biāo)識(shí),
這個(gè)標(biāo)識(shí)有時(shí)可以排除部分靜態(tài)庫(kù)代碼,只把有效的代碼導(dǎo)入項(xiàng)目。(見下段注解)

-ObjC編譯標(biāo)識(shí): (此段為譯者注)

例如,你的項(xiàng)目使用了第三方開源類JSONKit,而你的靜態(tài)庫(kù)也用到了這個(gè)JSONKit,那么你把靜態(tài)庫(kù)導(dǎo)入到項(xiàng)目后,這就產(chǎn)生沖突,所以你在把靜態(tài)庫(kù)導(dǎo)入項(xiàng)目時(shí),靜態(tài)庫(kù)里的JSONKit.h頭文件就不必導(dǎo)入,因?yàn)槟愕捻?xiàng)目里已經(jīng)有了JSONKit.h,JSONKit.m文件,使用-ObjC編譯標(biāo)識(shí),Xcode就會(huì)變得聰明,Xcode知道你的項(xiàng)目里已經(jīng)有了JSONKit的實(shí)現(xiàn)代碼,即JSONKit.m文件,所以,靜態(tài)庫(kù)的JSONKit.m文件就不會(huì)被導(dǎo)入,這樣,你的項(xiàng)目和靜態(tài)庫(kù)就共用你項(xiàng)目里面的JSONKit.m文件。你可以做一個(gè)相關(guān)實(shí)驗(yàn)嘗試一下,把項(xiàng)目和靜態(tài)庫(kù)里的JSONKit.m文件里的內(nèi)容寫的不一樣,看看,最終app里到底使用的哪個(gè)文件。

-ObjC編譯標(biāo)識(shí)功能很多,使用這個(gè)標(biāo)識(shí),可以讓靜態(tài)庫(kù)里的類和類別(categories)文件被合理的加載進(jìn)來(lái)。
你可以在Technical Q&A QA1490學(xué)習(xí)更多-ObjC編譯標(biāo)識(shí)相關(guān)知識(shí)。

添加-ObjC編譯標(biāo)識(shí)的方法如下圖,點(diǎn)擊Build Settings標(biāo)簽,在右上角的搜索框輸入Other linker 即可搜索到。

 Other linker Flags-search

Other linker Flags(不用展開該行)這行的后半空白部分雙擊,彈出下圖界面,點(diǎn)擊彈出框左下角的“+”按鈕,輸入-ObjC即可

 Other linker Flags-add -ObjC

最后,編譯、運(yùn)行你的app;你不會(huì)再看到任何編譯error,編譯成功,app將會(huì)運(yùn)行起來(lái),如下圖:

run success

你可以嘗試點(diǎn)擊app上的按鈕和滑動(dòng)條,看看具體效果。
執(zhí)行這些圖片變化效果的代碼并不在app,而是在靜態(tài)庫(kù)。

恭喜你!你剛剛在一個(gè)真實(shí)的app里編譯、運(yùn)行了你的第一個(gè)靜態(tài)庫(kù)。
包含頭文件和靜態(tài)庫(kù)文件的方法,已經(jīng)被用在很多知名的第三方庫(kù)里,
例如AdMob, TestFlight或者那些不想提供源代碼的商業(yè)庫(kù)(百度地圖、微博分享等等)。

方法2:將靜態(tài)庫(kù)作為子項(xiàng)目加載

對(duì)于這部分教程,你需要下載里一個(gè)文件,
點(diǎn)此下載

將下載好的zip文件拷貝你希望的位置,解壓zip,你會(huì)看到如下圖的文件結(jié)構(gòu)

method2-zip

如果你看了上面的方法1,你會(huì)注意到,這次解壓后的項(xiàng)目文件夾的根目錄和方法1的不同:
這個(gè)項(xiàng)目文件夾根目錄,沒有任何頭文件和.a文件(因?yàn)榉椒?不需要這些東西)。
取而代之,你將會(huì)看到,在本教程開始部分創(chuàng)建的ImageFilters靜態(tài)庫(kù)項(xiàng)目
作為子項(xiàng)目被添加到這個(gè)項(xiàng)目里。

在你做其它事情之前,你先編譯、運(yùn)行這個(gè)app,你將會(huì)被下圖的error問(wèn)候:

method2-error-1

如果你看過(guò)本教程的方法1,你可能已經(jīng)知道該如何修復(fù)這個(gè)error。
在你剛剛下載解壓的項(xiàng)目里,你在ViewController類里使用了ImageFilters
,但你仍然沒有告訴Xcode頭文件在哪里。你運(yùn)行該項(xiàng)目時(shí),Xcode找不到ImageFilters.h文件,所以編譯失敗。

為了把ImageFilters靜態(tài)庫(kù)項(xiàng)目導(dǎo)入進(jìn)來(lái)作為子項(xiàng)目,有2個(gè)方法:

  • 導(dǎo)入方法1:打開ImageFilters項(xiàng)目,你只需要從靜態(tài)庫(kù)項(xiàng)目窗口 拖曳 靜態(tài)庫(kù)項(xiàng)目的項(xiàng)目文件(一般為ImageFilters項(xiàng)目導(dǎo)航欄的最上面的那個(gè)文件) 到主項(xiàng)目(這里是CoreImageFun項(xiàng)目)窗口的導(dǎo)航欄中的任何地方即可,因?yàn)槟壳?strong>ImageFilters項(xiàng)目已經(jīng)在窗口中打開,所以在主項(xiàng)目窗口里顯示的ImageFilters文件只是單個(gè)文件,而不是樹狀結(jié)構(gòu)。你要關(guān)閉這兩個(gè)項(xiàng)目,然后再打開主項(xiàng)目CoreImageFun,你就會(huì)發(fā)現(xiàn)它已經(jīng)變?yōu)闃錉罱Y(jié)構(gòu)。如下圖
  • 導(dǎo)入方法2:先關(guān)閉ImageFilters項(xiàng)目,然后在文件夾中,找到靜態(tài)庫(kù)的項(xiàng)目文件(即ImageFilters.xcodeproj文件),拖曳該文件到主項(xiàng)目CoreImageFun的導(dǎo)航欄中即可。如下圖

add-subProject

注意:這兩個(gè)方法的最終效果是一樣的(如下圖),在執(zhí)行上面的方法2,盡量確保子項(xiàng)目(這里指的是ImageFilters靜態(tài)庫(kù)項(xiàng)目)并沒有在Xcode中打開,
否則的話,你需要關(guān)閉這兩個(gè)項(xiàng)目,再重新打開主項(xiàng)目。因?yàn)橥粋€(gè)項(xiàng)目,不能同時(shí)在兩個(gè)窗口中打開。

after add-subProject

現(xiàn)在Xcode知道了靜態(tài)庫(kù)子項(xiàng)目,你可以把添加靜態(tài)庫(kù)到項(xiàng)目依賴(Dependencies),如下圖操作。
這就意味著,Xcode將確保在編譯app前,靜態(tài)庫(kù)的代碼是最新的(就是說(shuō),如果靜態(tài)庫(kù)項(xiàng)目有代碼變更,主項(xiàng)目會(huì)自動(dòng)重新編譯靜態(tài)庫(kù)項(xiàng)目)。

Xcode添加項(xiàng)目依賴,如下圖操作1~4,

add-Dependencies

點(diǎn)擊上圖步驟4的“+”號(hào)按鈕會(huì)彈出另一個(gè)窗口,彈出的窗口如下圖,在下拉列表里選擇ImageFilters目標(biāo)(而不是universalLib),點(diǎn)擊右下角的“add”,完成。

add-Dependencies-pop

完成上面的添加依賴的步驟后,Build Phases標(biāo)簽的Target Dependencies部分,將會(huì)增加一條,如下圖:

after-add-Dependencies

最后一步,配置項(xiàng)目,將靜態(tài)庫(kù)連接到項(xiàng)目。如下圖,展開Link Binary with libraries部分.

Link Binary with libraries

點(diǎn)擊上圖的“+”號(hào)按鈕,彈出 下圖的界面,
選擇libImageFilters.a項(xiàng)目,點(diǎn)擊add

method2-add static lib

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

after-method2-add static lib

最后一步,添加-ObjC編譯標(biāo)識(shí),添加步驟與上面的方法1的最后一步一樣,如下圖:

method2 add ObjC

在上圖Other linker Flags行的后半空白部分雙擊,彈出如下圖,
點(diǎn)擊彈出框左下角“+”按鈕,添加 -ObjC。

after method2 add ObjC

編譯運(yùn)行你的app,app將會(huì)運(yùn)行成功,如下圖:

method2 success

你可以操作一下剛剛運(yùn)行成功的app。
與方法1一樣,圖片效果的邏輯代碼,都在靜態(tài)庫(kù)中。

如果你按照方法1試驗(yàn)過(guò)添加靜態(tài)庫(kù)的過(guò)程(使用頭文件和靜態(tài)庫(kù)),在處理方式上,和方法2有很多不同之處。
在方法2,你沒有為Xcode配置header search paths參數(shù)。
另一個(gè)不同之處,你沒有使用過(guò)通用靜態(tài)庫(kù)(Universal library)。

為什么會(huì)不同?
把靜態(tài)庫(kù)項(xiàng)目添加為子項(xiàng)目,Xcode就幾乎為你解決了所有事情。
添加子項(xiàng)目和依賴之后,Xcode就知道了在哪里找到頭文件和靜態(tài)庫(kù)文件,
而且靜態(tài)庫(kù)的架構(gòu)會(huì)根據(jù)你app選擇的參數(shù)來(lái)編譯,這真是夠方便的。

如果你使用自己的靜態(tài)庫(kù),或者你需要訪問(wèn)源碼和項(xiàng)目文件,
那么,導(dǎo)入靜態(tài)庫(kù)到項(xiàng)目較為方便的方法:方法2(即添加靜態(tài)庫(kù)項(xiàng)目作為子項(xiàng)目);
因?yàn)槟慵勺禹?xiàng)目作為項(xiàng)目依賴,你需要操作、擔(dān)心的事情就很少了,歐耶!

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

在靜態(tài)庫(kù)里經(jīng)常會(huì)遇到 圖片、xib、各種外部文件等等,這些不能放在靜態(tài)庫(kù)里,
通常的做法是:把這些文件打成一個(gè)bundle包(擴(kuò)展名為.bundle的文件)。
打bundle包,也可以建一個(gè)target,就像合并兩種架構(gòu)靜態(tài)庫(kù)的target的做法差不多。
具體做法點(diǎn)此

接下來(lái)去哪里?

你可以在這里下載這個(gè)教程的所有項(xiàng)目代碼。

對(duì)于靜態(tài)庫(kù)的基本概念、怎樣在自己的app使用靜態(tài)庫(kù),希望這個(gè)教程會(huì)對(duì)你有所幫助。

接下來(lái),用上面的知識(shí)去編譯你自己的靜態(tài)庫(kù)!
你肯定有需要添加到所有項(xiàng)目里的通用類,把這些代碼放在你自己的靜態(tài)庫(kù)里重用會(huì)是個(gè)很好的注意。
你還能夠根據(jù)功能分類,創(chuàng)建多個(gè)靜態(tài)庫(kù):
一個(gè)靜態(tài)庫(kù)放網(wǎng)絡(luò)交互的代碼,
一個(gè)放UI相關(guān)類的代碼,等等。
這樣你就能把你需要的模塊添加到項(xiàng)目里。

為了進(jìn)一步鞏固、更深一步學(xué)習(xí)本教程的內(nèi)容,
我也推薦你看看蘋果官方文檔里有關(guān)靜態(tài)庫(kù)的內(nèi)容
Introduction to Using Static Libraries in iOS

希望你能喜歡這個(gè)教程,如果你有任何問(wèn)題和想法,請(qǐng)加入論壇討論。


以下為譯者注

這篇文章使用Markdown語(yǔ)言編寫,使用了如下工具:

本人英語(yǔ)也不是太好,翻譯質(zhì)量不是太高,如有不妥之處,歡迎在下面留言,指點(diǎn)批評(píng)。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多