iOS静态库和动态库

来源:互联网 发布:linux文件强制锁 编辑:程序博客网 时间:2024/05/18 22:10

iOS静态库和动态库

静态库和动态库是什么,以及它们的区别,详细介绍可参考博文:iOS里的动态库和静态库,里面讲的很详细。

在这里记录下学习的过程

静态库

参考iOS静态库SDK制作(包含第三方静态库)

平时我们用的第三方SDK基本上都是静态库,静态库的几个特点:

  • 在App项目编译的时候会被拷贝一份编译到目标程序中,相当于将静态库嵌入了,所以得到的App二进制文件会变大。
  • 在使用的时候,需要手动导入静态库所依赖的其他类库。(比如说某个SDK中使用到了CoreMotion.framework,在使用的时候需要手动导入。有的SDK需要link十几个系统库,这个时候非常恶心,只能一个一个手动加,这是静态库一个很大的不便之处。)
  • 导入静态库的应用可以减少对外界的依赖,如果导入的是第三方动态库,动态库找不到的话应用就会崩掉,例如Linux上经常出现的lib not found
  • 静态库很大的一个优点是减少耦合性,因为静态库中是不可以包含其他静态库的,使用的时候要另外导入它的依赖库,最大限度的保证了每一个静态库都是独立的,不会重复引用。

创建静态库

选择如下的Cocoa Touch Static Library创建静态库

1

Build生成静态库,在Products文件夹中查看
2

如果在Edit Scheme中,Build Configuration中选择Debug(以下是我自己的试验)

  • 如果模拟器选择的是Generic iOS Device,会有Debug-iphoneos文件夹
    3

  • 如果模拟器选择的是其它的模拟器,会有Debug-iphonesimulator文件夹
    4

Debug-iphonesimulator文件夹下对应的libWZLib.a是对应模拟器的,可使用lipo -info libWZLib.a来验证,如:
验证1

输出信息如下,其架构为x86_64

input file libWZLib.a is not a fat fileNon-fat file: libWZLib.a is architecture: x86_64

同理可验证Debug-iphoneos文件夹下的libWZLib.a,其架构为armv7 arm64,表示对应真机


如果在Edit Scheme中,Build Configuration中选择Release,可生成其它的2个版本的静态库。Release表示真实环境,会把日志和断言都去掉。


上面生成的Debug-iphoneosDebug-iphonesimulator文件夹中,头文件WZLib.h是位于include/项目名下,如何让头文件,直接在include文件夹下呢?
Build Phases中的Copy Files中,去掉Subpathinclude/$(PRODUCT_NAME),后面的/$(PRODUCT_NAME)(表示工程文件名)即可:
5
删除原来生成的文件,Clean之后,再Build,此时头文件就直接在include文件夹下了
6

如果想添加多个头文件,选择Copy Files下的+号,如下:

7

静态库使用

如果把对应真机的静态库libWZLib.a和头文件,导入到项目中使用,则会提示错误:

8

所以要导入模拟器对应的版本

如果想同时支持模拟器和真机,该怎么做呢?
需要使用终端命令来合并
如下合并命令,表示把libWZLibR.a(真机版)和libWZLib.a(模拟器版),合并为test.a

lipo -create libWZLibR.a libWZLib.a -output test.a

此时lipo -info test.a,显示信息为:

Architectures in the fat file: test.a are: armv7 x86_64 arm64 

表示其支持模拟器和真机

要注意的问题

1.如果静态库内有 category 分类,那么需要在添加 -ObjC 编译标识,否则可能会报:unrecognized selector sent to instance

可参考:

  • iOS 中静态链接库的使用
  • iOS静态库中类的分类问题和符号冲突问题(Xcode other Link Flags)

使用Bundle打包图片配合静态库使用

可参考:

  • 使用Bundle打包图片配合静态库使用
  • iOS开发之静态库(三)—— 图片、界面xib等资源文件封装到.a静态库

由于静态库只能放代码不能带图片资源,有两种解决方案

  • 使用Framework<( ̄︶ ̄)>
  • 使用bundle打包图片文件和静态库分别打包拷贝给别人
  • 把图片素材传给别人

第三种方法这么坑,万一哪个文件再搞混了….所以推荐用第二种

新建工程:File -> New -> Project… -> OS X -> Framework & Library -> Bundle
我们必须借助于OS X,因为iOS框架中没有创建Bundle的模板

动态库

参考iOS静态库SDK制作(包含第三方静态库)

这个是我们最常用的一类库,使用频率最高的UIKit.framework和Fundation.framework都属于动态库,所有.dylib和.tbd结尾的都属于动态库。动态库的几个特点:

  • 平时使用的系统库都放在iOS系统中,在你打包应用程序的时候这些库不会拷贝到你的程序中,当需要使用的时候会动态从iOS系统中加载它们,因为这个原因,动态库也被称作共享库。编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。
  • 这些库是所有应用公用的,换一种说法就是节省了应用安装包的体积,这是区别静态库很重要的一个特点,因为静态库使用一次就要拷贝一次,非常浪费资源。
  • 动态库在制作的时候可以直接包含静态库,也能自动link所需要的依赖库。
  • 使用动态库的时候不需要再次link依赖库,即导即用,这个就厉害了。唯一需要注意的是在导入自己制作的动态库时,需要在Embedded Binaries中导入,不然会报错:image not found。此时这个动态库会跟静态库一样被拷贝到目标程序中进行编译,苹果又把这种Framework叫做Embedded Framework

关于动态库要搞清楚一点,我们自己制作的动态库与系统动态库的区别,我们自己制作的动态库引入App项目的时候需要embed进项目,也就是要拷贝到目标程序中,这就有点不像动态库的特性了,苹果这么做也是考虑安全问题吧!

创建动态库

9

添加相应的类后,在Build Phases下的Headers中,把Project下的头文件移动到Public即可,如下:
10

此时build,在工程的的Products目录下,生成WZFrame.framework。与静态库一样,也对应真机和模拟器版本

11

合并真机和模拟器的Framework

1.使用lipo -create,这种方式比较麻烦一点,生成后还需要替换,具体方式可参考:

  • iOS里的动态库和静态库
  • iOS创建.a和.framework静态库,以及Bundle资源文件的使用

2.在工程的Build Phases里添加以下脚本,真机和模拟器都Build一遍之后就会在工程目录下生成Products文件夹,里面就是合并之后的Framework

  • 新建New Run Script Phase
    15
  • 添加脚本
    16

    if [ "${ACTION}" = "build" ]thenINSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.frameworkDEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.frameworkSIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.frameworkif [ -d "${INSTALL_DIR}" ]thenrm -rf "${INSTALL_DIR}"fimkdir -p "${INSTALL_DIR}"cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"#open "${DEVICE_DIR}"#open "${SRCROOT}/Products"fi
  • 上面的脚本要保证真机和模拟器的framework都要存在,否则生成的framework会为空。此时生成的framework,在项目目录下
    16

此时使用lipo -info WZFrame,结果为:

Architectures in the fat file: WZFrame are: x86_64 armv7 arm64 

表示已合并成功

动态库使用

如果把刚才生成的动态库WZFrame.framework,导入并调用

#import <WZFrame/WZObject.h>[WZObject testMethod];

添加项目中来直接使用,会出现如下所示的错误

12

dyld: Library not loaded: @rpath/WZFrame.framework/WZFrame  Referenced from: /Users/Miller/Library/Developer/CoreSimulator/Devices/15E3C2C6-797C-40CF-A0F5-8DCA6E472AF1/data/Containers/Bundle/Application/2F13129C-2F69-48BC-B100-00A2D478C4B3/iOSLibTest.app/iOSLibTest  Reason: image not found

如何解决呢?
1.选择New Copy Files Phase
13

2.添加WZFrame.framework
14

原创粉丝点击