【翻译】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语言编写,使用了以下工具:

本人英语也不是太好,翻译质量不是过高,若有不妥之处,欢迎在下面留言,指点批评。

相关文章
相关标签/搜索