IOS培训
美国上市IOS培训机构

400-111-8989

热门课程

ios开发中动态库的使用教程

  • 发布:iOS培训
  • 来源:网络
  • 时间:2018-06-14 17:45

这篇文章讲的是在ios开发中关于动态库的使用,这一节我们ios培训课程中也是讲到过的。那么说起动态库我不由得还得给大家说一下库是什么?

库:是程序代码的集合,是共享程序代码的一种方式

根据源代码的公开情况,库可以分为2种:

1、开源库:公开源代码,可以看到具体的实现.SDWebImage、AFNetWorking

2、闭源库:不公开源代码,是经过编译后的二进制文件,看不到具体的实现.它主要分为:静态库、动态库

那么动态库是什么呢?

动态库又称动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL 副本的内容。DLL 是一个包含可由多个程序同时使用的代码和数据的库。Windows下动态库为.dll后缀,在linux下为.so后缀。

动态库的作用

应用插件化:

每一个功能点都是一个动态库,在用户想使用某个功能的时候让其从网络下载,然后手动加载动态库,实现功能的的插件化

虽然技术上来说这种动态更新是可行的,但是对于AppStore上上架的app是不可以的。iOS8之后虽然可以上传含有动态库的app,但是苹果不仅需要你动态库和app的签名一致,而且苹果会在你上架的时候再经过一次AppStore的签名。所以你想在线更新动态库,首先你得有苹果APPStore私钥,而这个基本不可能。

除非你的应用不需要通过AppStore上架,比如企业内部的应用,通过企业证书发布,那么就可以实现应用插件化在线更新动态库了。

共享可执行文件:

在其它大部分平台上,动态库都可以用于不同应用间共享,这就大大节省了内存。从目前来看,iOS仍然不允许进程间共享动态库,即iOS上的动态库只能是私有的,因为我们仍然不能将动态库文件放置在除了自身沙盒以外的其它任何地方。

不过iOS8上开放了App Extension功能,可以为一个应用创建插件,这样主app和插件之间共享动态库还是可行的。(还需了解下App Extension)

iOS上动态库可以做什么

和静态库在编译时和app代码链接并打进同一个二进制包中不同,动态库可以在运行时手动加载,这样就可以做很多事情,比如:

共享可执行文件

在其它大部分平台上,动态库都可以用于不同应用间共享,这就大大节省了内存。从目前来看,iOS仍然不允许进程间共享动态库,即iOS上的动态库只能是私有的,因为我们仍然不能将动态库文件放置在除了自身沙盒以外的其它任何地方。

不过iOS8上开放了App Extension功能,可以为一个应用创建插件,这样主app和插件之间共享动态库还是可行的。

创建动态库

上文提到过,动态库一般有两种,分别以.framework和.dylib后缀结尾,通常把它们叫做Framework和Shared Library。Framework本质上是由Shared Library加上头文件header和其他资源文件打包得来的。

下面以创建LibPersonFramework为例

1.创建一个新工程,选择iOS -> Cocoa Touch Framework

ios开发中动态库的使用教程

2.实现framework,并指定对外的头文件

定义头文件LibPerson.h

 

6#import <foundation foundation.h="">

@interface LibPerson : NSObject

@property (nonatomic, copy) NSString *name ;

- (void)watch;

- (void)eat;

@end</foundation>

指定LibPersonFramework.h和LibPerson.h为对外的头文件

ios开发中动态库的使用教程

指定framework的架构模式,这里选择了Generic iOS Device机型,然后build一下,就会创建一个通用mach-o文件,包含了arm64和arm_v7两种架构。如果选择了模拟器,会创建一个x86_64架构的mach-o文件。

ios开发中动态库的使用教程

需要注意的是,App和它依赖的framework的架构必须兼容,也就是说,在创建可执行文件时,要么都是真机,要么都是模拟器。当然,也可以分别在真机和模拟器两种模式下创建framwork,然后使用lipo命令来将两个framework内部的同名mach-o文件合并成一个通用mach-o文件,这样,不管App是什么架构模式,都能正确使用这个framework了。

使用动态库

添加动态库到工程文件

经过以上步骤的努力,生成了最终需要的framework文件,为了演示动态库的使用,新建了一个名为FrameworkDemo的工程。通过以下方式将刚生成的framework添加到工程中:

Targets-->Build Phases-->Link Binary With Libraries

同时设置将framework作为资源文件拷贝到Bundle中:

Targets-->Build Phases-->Copy Bundle Resources

如图所示:

ios开发中动态库的使用教程

仅仅这样做是不够的,还需要为动态库添加链接依赖。

自动链接动态库

添加完动态库后,如果希望动态库在软件启动时自动链接,可以通过以下方式设置动态库依赖路径:

 

Targets-->Build Setting-->Linking-->Runpath Search Paths

由于向工程中添加动态库时,将动态库设置了Copy Bundle Resources,因此就可以将Runpath Search Paths路径依赖设置为main bundle,即沙盒中的FrameworkDemo.app目录,向Runpath Search Paths中添加下述内容:

 

@executable_path/

如图所示:

ios开发中动态库的使用教程

其中的@executable_path/表示可执行文件所在路径,即沙盒中的.app目录,注意不要漏掉最后的/。

如果你将动态库放到了沙盒中的其他目录,只需要添加对应路径的依赖就可以了。

需要的时候链接动态库

动态库的另一个重要特性就是即插即用性,我们可以选择在需要的时候再加载动态库。

更改设置

如果不希望在软件一启动就加载动态库,需要将

Targets-->Build Phases-->Link Binary With Libraries

中Dylib.framework对应的Status由默认的Required改成Optional;或者更干脆的,将Dylib.framework从Link Binary With Libraries列表中删除即可。

使用dlopen加载动态库

以Dylib.framework为例,动态库中真正的可执行代码为Dylib.framework/Dylib文件,因此使用dlopen时如果仅仅指定加载动态库的路径为Dylib.framework是没法成功加载的。

示例代码如下:

- (IBAction)onDlopenLoadAtPathAction1:(id)sender

{

NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/Dylib.framework/Dylib",NSHomeDirectory()];

[self dlopenLoadDylibWithPath:documentsPath];

}

- (void)dlopenLoadDylibWithPath:(NSString *)path

{

libHandle = NULL;

libHandle = dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);

if (libHandle == NULL) {

char *error = dlerror();

NSLog(@"dlopen error: %s", error);

} else {

NSLog(@"dlopen load framework success.");

}

}

以dlopen方式使用动态库不知道是否能通过苹果审核。

使用NSBundle加载动态库

也可以使用NSBundle来加载动态库,实现代码如下:

- (IBAction)onBundleLoadAtPathAction1:(id)sender

{

NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/Dylib.framework",NSHomeDirectory()];

[self bundleLoadDylibWithPath:documentsPath];

}

- (void)bundleLoadDylibWithPath:(NSString *)path

{

_libPath = path;

NSError *err = nil;

NSBundle *bundle = [NSBundle bundleWithPath:path];

if ([bundle loadAndReturnError:&err]) {

NSLog(@"bundle load framework success.");

} else {

NSLog(@"bundle load framework err:%@",err);

}

}

使用动态库中代码

通过上述任一一种方式加载的动态库后,就可以使用动态库中的代码文件了,以Dylib.framework中的Person类的使用为例:

- (IBAction)onTriggerButtonAction:(id)sender

{

Class rootClass = NSClassFromString(@"Person");

if (rootClass) {

id object = [[rootClass alloc] init];

[(Person *)object run];

}

}

注意,如果直接通过下属方式初始化Person类是不成功的:

- (IBAction)onTriggerButtonAction:(id)sender

{

Person *object = [[Person alloc] init];

if (object) {

[object run];

}

}

监测动态库的加载和移除

我们可以通过下述方式,为动态库的加载和移除添加监听回调:

+ (void)load

{

_dyld_register_func_for_add_image(&image_added);

_dyld_register_func_for_remove_image(&image_removed);

}

github上有一个完整的示例代码,

从这里看出,原来就算空白工程软件启动的时候也会加载多达一百二十多个动态库,如果这些都是静态库,那该有多可怕!!

Demo

本文使用的例子已经上传到github上,需要的朋友请自取。

另外,本文对某些东西可能有理解错误的地方,还请指出。

总结:本文总述都是关于动态库的讲解,说要说明了库与动态库的含义、动态库的作用、iOS上动态库可以做什么及创建动态库的方法教程。希望以上内容可以为ios开发者在工作中起到帮助作用,更多的关于ios开发相关教程在ios培训官网每日都有更新。关注官网动态即可。

免责声明:内容和图片源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容

预约申请免费试听课

上一篇:作为小白如何学习ios软件开发
下一篇:ios开发中的耳返功能实现

IOS库开发知识点总结和归纳

IOS Swift实战开发经验总结,IOSSwift开发经验分享

IOS设计 - 一款APP从设计稿到切图过程概述

2017年IOS开发者账号申请以及邓白氏码的申请教程经验

选择城市和中心
贵州省

广西省

海南省