iOS - 动态库及静态库的使用

开篇

想要构建一个高逼格的应用程序,库的应用必不可少,同时想要真正进入iOS开发的世界”库“是我们要掌握的。

那儿_并不远

iOS中库的相关概念

  • ** 库 **:就是一段已经编译好的二进制代码,加上头文件就可以提供给其他人使用了。iOS中常见的有 .a,.dylib,.Framework等结尾的库。

  • ** 库的分类 **:开源库和闭源库
    **(1)开源库 **:比如我们常用的AFNetworking,源码都是开发给我们开发者的,下载后copy到项目中可以直接使用。在开发中我们常用的是cocoapods,用命令直接导入开源库,不用关心开源库的相关依赖。其实cocoapods的本质是将开源库编译成静态库,然后使得主工程依赖此静态库。
    **(2)闭源库 **:可以分为静态库和动态库,像我们开发时用到的百度地图等三方框架就会用到很多闭源库。

  • ** 深入理解静态库和动态库 **
    **(1)静态库 **:它是你的.m文件编译而成的二进制文件集合,需要配合暴漏在外面的.h文件使用,在程序编译的时候会被直接copy到目标程序中,在编译完成之后,库文件实际就没有多大作用了,目标程序没有外部依赖,可以直接运行,所以缺点就是导致目标程序的体积增大。
    **(2)动态库 **:它也是你的.m文件编译而成的二进制文件集合,需要配合暴漏在外面的.h文件使用,但是不同的是,在编译时动态库不会被copy到目标程序中,目标程序只会存储指向动态库的引用,等到程序运行时,动态库才会被真正加载进来。不会影响目标程序的体积,但是会带来一部分性能损失。而且目前苹果不允许自制的动态库上架到AppStore

  • ** 使用静态库和动态库的好处 **
    **(1)静态库 **:模块化,可以避免少量改动经常导致大量的重复编译连接,也可以重用,但注意不是共享使用。
    **(2)动态库 **:可以将最终的可执行文件体积缩小,多个应用程序共享内存中的同一份库文件,达到节约资源的效果,也可以不重新编译连接可执行程序的前提下,更新动态库文件达到更新应用程序的目的。但是可悲的是苹果不允许自制的动态库上架到AppStore,但是可以开发公司内部的应用程序还是比较方便的。

创建静态库和动态库

下面我们就先分别创建静态库和动态库,然后将我们创建的静态库和动态库应用到我们的项目中,这样便于大家更好的理解静态库和动态库,也方便大家更好的构建自己的项目或框架


** 说明 **:我写一个小Demo,Demo的功能是改变UIImage的颜色,我会分别创建静态库和动态库来实现不同的功能模块(当然,都可以创建为静态库,但是为了让大家更清楚两种库的创建步骤)
(1)静态库:封装资源文件(.bundle文件)用来存放图片,封装返回图片路径的方法并提供外界 .h 文件
(2)动态库:封装改变UIimage的颜色的方法并提供外界 .h 文件。

** 顺便说一下Bundle文件,Bundle文件是静态的,也就是说,我们包含到包中的资源文件作为一个资源包是不参加项目编译的。也就意味着,bundle包中不能包含可执行的文件。它仅仅是作为资源,被解析成为特定的2进制数据。**


  • ** (1)创建静态库 **
    第一步:打开Xcode,会弹出下面的选择框,然后大家选择标记处,然后为静态库命名并创建。
(1)

创建成功后大家可以看到,Products下的libStaticLibraryTest.a文件是红色的,不要方,command+B编译或者run一下就好了,静态库是程序编译是copy到目标程序中的。如下图,系统已经为我们创建好了一个以工程名命名的 .h 和 .m 文件。你可以用也可以不用,我就直接用了


(2)

第二步:创建一个Bundle文件,command+N就会弹出下面的选择框,然后选择标记并命名创建
![Uploading 屏幕快照 2016-11-17 上午1.06.21_068118.png . . .]

(3)

如下图,Bundle文件创建成功后,我向其中放入一张图片


(4)

第三步:添加Bundle文件到Copy File中,targets -> build phases -> copy files,如下图所示

(5)

第四步:写相关方法

(1)在StaticLibraryTest.h提供对外方法接口

#import <Foundation/Foundation.h>

@interface StaticLibraryTest : NSObject

+ (NSString *)getImagePathWithBundleName:(NSString *)bundleName ImageName:(NSString *)imageName Type:(NSString *)type;

@end

(2)在StaticLibraryTest.m中实现方法

#import "StaticLibraryTest.h"

@implementation StaticLibraryTest

+ (NSString *)getImagePathWithBundleName:(NSString *)bundleName ImageName:(NSString *)imageName Type:(NSString *)type {
    
    NSString *bundlePath = [[NSBundle mainBundle] pathForResource:bundleName ofType:@"bundle"];
    NSString *path = [NSString stringWithFormat:@"%@/%@.%@", bundlePath, imageName, type];
    return path;
    
}

@end

第五步:执行程序,command+R,这样我们的静态库就生成好了,点击libStaticLibraryTest.a,然后show in fender,我们会看到下面我们生成了针对于模拟器的静态库,注意我们command+R是在模拟器中run的,如果想生成针对真机的静态库,必须在真机下run,然后可以通过lipo -create -output命令在终端合并两个静态库文件,这样我们就得到一个既可以在真机又可以在模拟器上使用的静态库了(这里不多说了)。应用时我们就将标记处copy到我们的项目中,就可以直接使用了

(6)
  • ** (2)创建动态库 **

第一步:打开Xcode,会弹出下面的选择框,然后大家选择标记处,然后为静态库命名并创建。

(7)

创建完成后如图所示

(8)

第二步:创建一个ChangeImageColor类,用来写改变图片颜色的方法

ChangeImageColor.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface ChangeImageColor : NSObject

+ (UIImage *)changeImageColorWithColor:(UIColor *)color Image:(UIImage *)image;

@end

ChangeImageColor.m

#import "ChangeImageColor.h"

@implementation ChangeImageColor

+ (UIImage *)changeImageColorWithColor:(UIColor *)color Image:(UIImage *)image
{
    
    UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0, image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
    CGContextClipToMask(context, rect, image.CGImage);
    [color setFill];
    CGContextFillRect(context, rect);
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
    
}

@end

第三步:设置开放的头文件可以通过target—>build phases—>headers来设置,如下图

(9)

同时可以在DynamicLibraryTest.h中倒入自己创建类的头文件


(10)

第四步:通用动态库
** 经过以上三步我们只是创建了一个动态库文件,但是和静态库类似,该动态库并同时不支持真机和模拟器,可以通过以下步骤创建通用动态库 **

  • 创建Aggregate,并命名创建。
(11)
  • 设置Target Dependencies,targets -> Common -> Build Phases -> Target Dependencies,将动态库添加到Target Dependencies中
(12)
  • 添加Run Script
(13)
  • 添加脚本,复制粘贴就好
# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMK_NAME,否则不需要改动
FMK_NAME=${PROJECT_NAME}

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# -configuration ${CONFIGURATION} 
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"

rm -r "${WRK_DIR}"

脚本添加完后,command+B执行程序即可,在show in finder找到我们生成的动态库,如图,同样我也只生成了模拟器的动态库,和静态库原理相同,可通过终端来合成真机和模拟器共用的动态库

(14)

应用静态库和动态库

通过以上步骤我们已经分别生成了静态库和动态库,接下来我们就开始运用了,很简单,一步一步来就好.

  • 第一步:创建一个工程,这里多说了。
  • 第二部:将静态库和动态库copy到工程中,添加后如图所示
(15)

** 但是这时候需要注意了,静态库copy到文件中可以直接使用,但是对动态库必须添加依赖路径**

  • 第三步:添加完动态库后,同时设置将framework作为资源文件拷贝到Bundle中,Targets-->Build Phases-->Copy Bundle Resources,如下图所示,
(16)

** 好了现在我们就将静态库和动态库copy到了我们的工程中,这时我们就可以使用了。**

项目实战

接下来我在工程中的 ViewController.m 文件中代码如下

#import "ViewController.h"

// 引入静态库中文件
#import "StaticLibraryTest.h"

// 引入动态库
#import <DynamicLibraryTest/DynamicLibraryTest.h>

@interface ViewController ()

@property (nonatomic, strong) UIImageView *imageOfTest;

@property (nonatomic, strong) UIButton *button;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    [self createSubView];
    
}



- (void)createSubView {
    
    
    self.imageOfTest = [[UIImageView alloc] initWithFrame:CGRectMake((self.view.frame.size.width - 50) / 2, 200, 50, 50)];
    
    // 静态库中提供的方法
    NSString *imagePath = [StaticLibraryTest getImagePathWithBundleName:@"Resource" ImageName:@"advantage" Type:@"png"];
    self.imageOfTest.image = [UIImage imageWithContentsOfFile:imagePath];
    
    [self.view addSubview:self.imageOfTest];
    
    self.button = [[UIButton alloc] initWithFrame:CGRectMake(20, 450, self.view.frame.size.width - 40, 50)];
    self.button.backgroundColor = [UIColor cyanColor];
    [self.button setTitle:@"change color" forState:UIControlStateNormal];
    [self.view addSubview:self.button];
    [self.button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    
    
}

- (void)buttonAction:(UIButton *)button {
    
    NSLog(@"改变颜色");
    
    UIImage *image = nil;
    // 利用动态库中提供方法实现
    if (button.selected == NO) {
        image = [ChangeImageColor changeImageColorWithColor:[UIColor blueColor] Image:self.imageOfTest.image];
    }
    else {
        image = [ChangeImageColor changeImageColorWithColor:[UIColor blackColor] Image:self.imageOfTest.image];
    }
    self.imageOfTest.image = image;
    
    button.selected = !button.selected;
    
}

总结

这次博客写的长了点,也许不会有太好的阅读效果,本来想拆分着写了,但是总感觉那样对技术的提高不算大。希望大家谅解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352

推荐阅读更多精彩内容