在 Xcode 提供的构建设置中,有一项称为“MACH_O_TYPE ”,其作用是定义输出的产品文件格式以及产品文件用于其他产品构建时如何被链接。它的取值如下所示:
1、可执行文件(mh_execute)(.app)
2、动态链接库(mh_dylib)(.dylib)
3、包(mh_bundle)(.bundle)
4、静态链接库(staticlib)(.a)
5、可重定位的对象文件(mh_object)(.o)
作为iOS开发者,基本上只要关心可执行文件、Bundle和静态链接库就可以了。动态链接库没法用,而静态库(archieve)是.o的文件包,所以静态库完全可以替代.o文件。
出于某些目的,比如设计架构上将功能与展现相分离,或者重要功能与边缘功能相分离,或者只是为了模块功能划分的清晰性等等,软件在设计时可能会分成几个工程来做。而对于iOS程序来说,最终提供给移动端用户的产品只能是ipa,即一个可执行程序,而其他工程所能提供的只能为其服务。这时程序员所能选择的只有bundle或者静态库。本文将就静态库的一些使用经验、技巧做出叙述,对于bundle的使用,将在另外的文章里进行叙述。
最后稍微科普一下动态链接库和静态链接库:
静态链接是在编译时进行的,静态链接库(.a文件)实际上就是编译好的程序代码,如果有两个程序都用到了同一个库的话,且同时运行这两个程序,那么内存中会有两份相同的库的代码。动态链接是在运行时进行的,由操作系统管理,如果两程序都用同一个DLL的话,实际上内存中只有一份代码。由于iOS开发严格的权限管理,即基本只限于沙盒内,所以动态链接库这种东西是不准使用的。
1.静态链接库(.LIB):函数和数据被编译进一个二进制文件。发布时,只需要发布这个可执行文件,并不需要发布被使用的静态库。
2.动态库(.DLL):在使用动态库的时候,往往提供两个文件:一个引入库(.lib)文件和一个DLL(.dll)。虽然引入库和静态库的后缀名相同,但是差别很大。对于一个DLL来说,其引入库文件包含该DLL导出的函数和变量的符号名,而.dll文件包含DLL的实际的函数和数据。在使用动态链接库的情况下,在编译链接可执行文件时,只需要DLL的引入库文件,而在运行可执行程序时,需要加载所需要的DLL,发布产品时,需要发布调用的动态链接库。
二、使用库的优势
1,模块化,分工合作
2,避免少量改动导致大量的重复编译连接
①共享给谁?(因为在现在的iPhone,iPodTouch,iPad上面程序都是单进程的,也就是某一时刻只有一个进程在运行,你使用的时候只有你一个应用程序存在,其他的应该被挂起了,即便是可以同时多个进程运行,别人能使用你的共享库里的东西吗?你这个是给你自己的程序定制的。)
四、Xcode对于创建库的支持
深入理解framework(框架,其实相当于静态框架,不是动态库)
打包framework还是一个比较重要的功能,可以用来做一下事情:
(1)封装功能模块,比如有比较成熟的功能模块封装成一个包,然后以后自己或其他同事用起来比较方便。
(2)封装项目,有时候会遇到这个情况,就是一家公司找了两个开发公司做两个项目,然后要求他们的项目中的一个嵌套进另一个项目,此时也可以把嵌套的项目打包成framework放进去,这样比较方便。
要想用一种开发者友好的方式共享库是很麻烦的。你不仅仅需要包含库本身,还要加入所有的头文件,资源等等。
Xcode仍然可以支持创建框架的功能,重启这个功能,我们需要对Xcode做一些小小的改动。
把代码封装在静态框架是被app store所允许的。尽管形式不同,本质上它仍然是一种静态库。
框架(Framework)的类别
大部分框架都是动态链接库的形式。因为只有苹果才能在iOS设备上安装动态库,所以我们无法创建这种类型的框架。
静态链接库和动态库一样,只不过它是在编译时链接二进制代码,因此使用静态库不会有动态库(运行时载入)那样的问题(即除了苹果谁也不能在iOS上使用动态库)。
“伪框架”模板把整个过程分为几个步骤,用某些脚本去产生一个真正的静态框架(基于静态库而不是reloacatable object file)。而且,框架项目还是把它定义为wrapper.cfbundle类型,一种Xcode中的“二等公民”。
六、iOS静态框架的创建、编译和使用
1、安装框架模板
要想在xcode中创建静态框架,须得先安装相应的模板iOS Universal Framework Mk
iOS Universal Framework Mk 8的下载地址:https://github.com/kstenerud/iOS-Universal-Framework
解压下载文件,打开Terminal,进入到刚下载文件,Fake Framework下面。输入命令:sh install.sh。同理安装Real Framework下的文件。安装完毕如下图:
分别运行Real Framework目录或Fake Framework目录下的install.sh脚本进行安装(或者两个你都运行)。
重启Xcode,你将在新项目向导的Framework&Library下看到StaticiOS Framework(或者Fake Static iOS Framework)。
若要卸载这两个模板,请运行unistall.sh脚本并重启Xcode。
2、 创建一个IOS框架项目
①创建新项目。
②项目类型选择Framework&Library下的Static iOS Framework(或者Fake Static iOS Framework)。
③ 选择“包含单元测试”(可选的)。
④在target中加入类、资源等。
⑤凡是其他项目要使用的头文件,必需声明为public。进入target的Build Phases页,展开Copy Headers项,把需要public的头文件从Project或Private部分拖拽到Public部分。
3、 编译IOS框架、
① 选择指定target的scheme。
②修改scheme的Run配置(可选)。Run配置默认使用Debug,但在准备部署的时候你可能想使用Release。
③编译框架(无论目标为iOS device和Simulator都会编译出相同的二进制,因此选谁都无所谓了)。
④从Products下选中你的framework,“show in Finder”。
在build目录下有两个文件夹:(yourframework).framework and (your framework).embeddedframework.
如果你的框架只有代码,没有资源(比如图片、脚本、xib、coredata的momd文件等),你可以把(yourframework).framework 分发给你的用户就行了。如果还包含有资源,你必需分发(your framework).embeddedframework给你的用户。
为什么需要embedded framework?因为Xcode不会查找静态框架中的资源,如果你分发(your framework).framework, 则框架中的所有资源都不会显示,也不可用。
一个embedded framework只是一个framework之外的附加的包,包括了这个框架的所有资源的符号链接。这样做的目的是让Xcode能够找到这些资源
4、 使用静态框架
iOS框架和常规的Mac OS动态框架差不多,只是它是静态链接的而已。
在你的项目中使用一个框架,只需把它拖仅你的项目中。在包含头文件时,记住使用尖括号而不是双引号括住框架名称。例如,对于框架MyFramework:
#import <MyFramework/MyClass.h>
七、静态库.a文件的编写
IOS产生.a的静态库,比起.framework相对简单了好些。
下面介绍一下具体生成步骤:
1、新建一个framework&library库。IOS 下的cocoa touch static library。然后输入product name 为libsql
2、把libsql.h和libsql.m删除。导入ocsqlite.h和ocsqlite.c(文件见http://blog.csdn.net/fengsh998/article/details/8278978)
3、修改scheme,设为release版本。
OK,选译ios device编译运行。成功后将在目录的build/products/release-iphoneos/下产生一个liblibsql.a文件。
注,这里产生的是真机使用的.a文件。
选译iphonesimulator 进行编译一次,同样会在build/products/release-iphonesimulator/下产生一个liblibsql.a文件。
这里是虚拟机使用的.a文件。
下面来看一下这两个文件有什么不同之处,使用lipo -info命令。
打开终端。
进入到相应的目录。
真机的:liblibsql.a文件信息。
input file liblibsql.a is not a fat file
Non-fat file: liblibsql.a is architecture: armv7
如图:
模拟器的:liblibsql.a文件信息。
input file liblibsql.a is not a fat file
Non-fat file: liblibsql.a is architecture: i386
如图:
如果使用真机和模拟器通用,则需要将这两个文件合并,使用命令lipo -create xxxx/liblibsql.a xxxxx/liblibsql.a -output libsql.a
同样可以使用lipo -info 来查看这个合并的libsql.a
可以看到architectures in the fat file: libsql.a are: i386 armv7
如图:
八、iOS中创建,使用动态库(dylib)
由于苹果不支持自己创建动态库,所以这里需要替换两个文件
①iOS Device 需要替换的文件
替换路径:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Specifications/
②iOS 模拟器需要替换的文件
替换路径:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications
具体可参照:http://blog.iosplace.com/?p=33 或者 http://www.cocoachina.com/bbs/simple/?t129814.html
替换完成后重启Xcode。
创建动态库
1:打开Xcode,新建项目,选择OS X --> Cocoa Library -->输入动态库的相关信息
2:这样,动态库已经创建好,但是由于此项目是基于Mac OS X创建的,所以这里要将project的相关设置作修改
1:Base 设置成 SDK iOS6.0
2:Architectures 设置成 standrand (armv7 armv7s)
3:Installation Directory 设置成 @executable_path/
4:Mach-O Type 设置成 Dynamic Library
5:Executable Prefix 设置成 空
6:打开项目的project.pbxproj(文本编辑器打开)文件,在编辑器中将producttype 的值修改为 com.apple.product-type.library.dynamic
7:选择合适的证书文件
3:将debug改为no
4:在动态库的相关类中添加一些测试方法
5:删除多余的framework文件。值添加Foundation.framework文件
Xcode--->Preferences--->Locations--->Advanced---->
这样基本就可以编译dylib了,但是这里还有一个需要注意的地方。
编译分为设备编译(iOS Device)及模拟器编译(iPad/iPhone Simulator)
在选择设备编译的时候,一定要选择某个有效的开发者证书。否则编译会出错。
相反,选择模拟器编译的时候,不需要选择证书(如果选了证书,也会报错)。