zoukankan      html  css  js  c++  java
  • iOS静态库相关-封装lib

    来源:http://blog.csdn.net/zsomsom/article/details/9163635

    Library介绍

    基本知识

    在实际的编程过程中,通常会把一些公用函数制成函数库,供其它程序使用,一则提搞了代码的复用;二则提搞了核心技术的保密程度。

    Library使用的两种方式:封装lib.a和直接引用lib工程。

    一、封装.a文件

    直接封装lib.a,向使用者提供头文件列表。使用者引用头文件并且使用其中方法,但是看不到实现文件的内容。这种方式每当静态库函数需要修改时就必须重新生成lib.a提供给使用者更换,比较麻烦,但有助于保密。

    制作静态库

    New Project -> iOS Library ->Cocoa touch Static Library 这样就新建了一个静态库的工程,将你要打包成lib的.m,.h放到class目录下面,然后选择build就可以了. 

    Bulid之后,在工程目录下Produces文件夹下可以看到生成的.a文件引用,右键,show in finder可以看到.a文件。

    要注意Build时的选项:

    <1>iOS Device编译出来的是在Debug-iphoneos目录下,真机使用,终端,在该目录下使用lipo -info **.a 可以查看你到文件类型为armv7等ARM架构。

    <2>Simulator时编译出来的是在Debug-iphonesimulator目录下,模拟器使用,终端查看类型显示为i386架构。

    可以使用lipo命令生成一个通用二进制lib.a lipo -create **/**.a **/**.a -output **/**.a 生成一个兼容两种类型的.a文件。方法虽好,但是包大小会增加。

    <3>.a文件所在木有没有include文件夹,如何设置?

    在项目Target设置页面选择Build Phases,然后选中里面的某一项(必须选择一下,否则后面的操作不能进行),然后菜单栏Editor->add Build Phases->Add Copy Build Phases即可生成Copy Files,在里面配置生成的路径及需要生成的头文件,选择Product Directory,路径例如:include/$(PRODUCT_NAME),然后Clean-Build即可发现.a文件所在目录多了一个include目录,包含了配置好的头文件。

    使用静态库

    在需要调用静态库的工程的目录下通过右键点 Frameworks->Add->Existing Files..添加之前创建的.a静态库文件,然后在需要调用静态库的函数的文件里,import进来静态库中.h头文件,这样就可以使用静态库里的函数了。(此处可以做一个头文件包含静态库中所有的头文件,只需声明这一个头文件就可以使用所有的相应头文件的方法)

    问题及注意事项

    0. .a文件路径:/Users/user/Library/Developer/Xcode/DerivedData/****/Build/Products/

    不同模式下可以生成不同类型的.a文件 真机/模拟器与Debug/Release选项公交叉成4种.a文件。     

    1.打包分清楚是debug与Release的。

    选择debug与Release在Xcode工具栏的Product选项现则Scheme->Edit Scheme.然后为各个运行模式选择选项。    

    2.分清楚lib是i386(真机)或者ArmV7(模拟器)模式

    终端下使用命令 lipo -info libPrint.a 可以查看.a的属性。如结果:libPrint.a is architecture(构建): armv7 

    3.把真机运行和模拟器运行的.a文件合并生成通用的.a文件,完成通用的静态库。

    终端使用命令 lipo -create 真机.a路径 模拟器.a路径 -output 目标路径(如/users/user/desktop/***.a)。然后info查看合并后.a的信息就会发现它已经同时具备了armv7和i386的条件

    4.在Build Phases->Compile Source中的文件,表示这些代码会被编译进lib中,你可以删掉你不希望被编译的。

    5.标准的Unix引入惯例是一个include文件夹,用来存放所有引用的外部头文件,一个lib文件夹用来存放库文件(.a)。这种文件夹结构这是一种惯例,并不强制。

    附:自动生成通用lib.a

    生成通用二进制lib.a需要lipo,一个命令行工具,它允许在通用文件上执行操作(类似于创建通用二进制, 列出通用文件内容等等)。本教程中使用lipo的目的是联合不同架构的二进制文件到单个输出文件中。你可以直接在命令行中使用lipo命令,但在本教程中你可以让Xcode执行一段创建通用库的命令行脚本来为你做这件事。

    Xcode中一个集合目标可以一次构建多个目标,包括命令行脚本。在选中lib工程文件,点击+号增加新的Target,选择iOS/Other并点击Aggregate,如下图:

    将目标命名为UniversalLib,确保选中你的lib工程中。然后选择UniversalLib Target。切换到Build Phases标签;点击+号增加Add Run Script Build Phase,如下图:

    现在你需要设置脚本项。展开Run Script模块,在Shell行下粘贴如下代码:

    # define output folder environment variable

    UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

    TARGET_NAME=ProjectName

    # Step 1. Build Device and Simulator versions

    xcodebuild -target ${TARGET_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"

    xcodebuild -target ${TARGET_NAME} -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}/"

    注意:修改其中的TARGET_NAME=ProjectName为你的lib工程名。

    代码并不十分复杂,它是这样工作的:

    UNIVERSAL_OUTPUTFOLDER 包括了通用二进制包将要被存放的文件夹:“Debug-universal”

    Step 1. 第2行执行了xcodebuild并命令它构建ARM架构的二进制文件。

    下一行再次执行了xcodebuild命令并在另一个文件夹中构建了一个针对Inter架构的iPhone模拟器的二进制文件,在这里关键参数是-sdk iphonesimulator -arch i386。

    Step 2. 现在已经有了2个.a文件分别对应两个架构。执行lipo -create,用它们创建出一个通用二进制。

    最后一行的作用是复制头文件到通用构建文件夹的外层。

    现在你已经准备好构建一个静态库的通用版本。

    选择UniversalLib然后Run,你就会在产品目录发现一个新的文件夹Debug-Universal或者Release-Universal,里面包含了合并之后的lib.a以及头文件。

    详细操作参考链接:http://www.cocoachina.com/applenews/devnews/2013/1204/7468.html

    二、引用lib工程

    静态库工程被包含在项目工程中或者与项目工程放在同一个WorkSpace中,做成联调静态库。这种方式的静态库工程与项目工程一起使用,故没有对Libray中的代码进行封装,可以查看修改。

    创建联调工程   

    1.在工程的Targets上右键.Add -> New Target -> Static Library 比如我们建了一个LibExample的target。这样是一个工程包含多个Target的形式,没有新建Lib工程。创建好Target之后你会发现原来的工程下面会多出几个文件夹:LibExample和LibExampleTest,用来存放跟Library相关的代码。

    另外,也可以直接在原工程上右键新建一个lib工程,或者在工程中右键add Existing File..增加已经存在的lib工程进来(不要选择copy to folder)。这种形式是一个工程下面包含一个Lib工程。

    2.在LibExample的目录中增加你需要加入的.h.m文件,然后查看在Build Phases->Compile Source中的文件,表示这些代码会被编译进lib中,你可以删掉你不希望被编译的,增加你想要编译进去的文件。

    3在工程的target上双击,targets->Build Phases里面Target Dependencies里面增加lib工程的target,这样编译工程时也会编译lib工程生成lib.a文件。同时在Link Binary With Libraries中增加选择lib.a,表示对library库的引用。 

    4.使用Lib工程而非Target时,需要修改工程的Scheme->Build中增增加Lib工程的Target。这样才能编译工程的同时编译lib工程,生成.a。

    5.引用lib头文件:在项目文件工程文件的target的build Setting->Header Search Paths中增加头文件路径(../文件名(lib工程文件名/ 例如../MyLibPrint/),这个路径适应于lib工程与项目工程在同一目录),选择成递归类型。

    6.最后在工程中可以使用lib.a中的文件了,使用时引用一下lib工程的头文件,如果不报错说明头文件引用成功,然后就可以使用了。

    Lib相关部分错误信息

    1.undefine symbols for architecture i386 错误。

    其实这个错误原因很简单,就是因为,我们用错了编译出来的libUITab.a lib,

    在模拟器里面,我们需要的是基于i386构架编译的static lib,但是这个a文件,大家还记得前面说的arm6 arm7构架的么。这个a其实是在iphone这个arm构架上运行的代码。

    那如何编译i386的库呢?运行之前选择Print>IOS Device,将这个iOS Device修改成iPhone5.0 Simulator。在进行编译,这样就可以编译出i386下面的库。

    下面最多有四个文件夹分别命名为:Debug-iphoneos/Debug-iphonesimulator/Release-iphoneos/Release-iphonesimulator这四条目录每个目录下同样也有一个libPrint.a文件。Release-iphoneos里面的是基于arm6 arm7编译出来的库文件。Release-iphonesimulator文件夹下面的是基于i386编译出来的文件。

    2.在编译RegexKitLite的时候,报错如下:

    在项目的编译设置中找到Other Linker Flags,然后在后面字段空白处双击,添加“-licucore”就可以了,引用正则框架必须打开此开关。-licucore,注意不要打错,打错了会报错误:clang: error: no such file or directory: ‘-licucore'

    对64bit的支持

    Xcode5.1生成的项目,默认的便已选择是支持64bit编译的,可以查看工程的build Setting中的Architectures选项,包含了arm64的设置。

    项目支持arm64要求项目中所引用的lib.a和.framework文件均支持arm64,否则就会报错。

    ld: symbol(s) not found for architecture x86_64

    当然,可以直接设置项目不支持x86_64。

    • build Settings中在Architectures选项设置为armv7和armv7s
    • Valid Architectures中删除arm64

    但是能兼容肯定是更好的:

    • lib或者framework工程创建是需要包含对arm64的支持。查看上述选项如果没有需要添加。
    • 使用lipo -info查看是否包含x86-64,判断是否成功。

    使用本文中的通用工程生成时,在模拟器编译时需要修改为如下,

    xcodebuild -target ${TARGET_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 -arch x86_64 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"

    增加ONLY_ACTIVE_ARCH=NO和-arch x86_64。然后编译即可生成符合要求的.a。

    其他参考

    Library官方文档:https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Introduction.html#//apple_ref/doc/uid/TP40012554-CH1-SW1

    XCode的各种参数配置参考:http://www.cnblogs.com/xiaodao/archive/2012/03/28/2422091.html

  • 相关阅读:
    更新主窗口控件的内容1:子线程工作时同时更新主线程内的控件内容
    静态类和非静态类中静态变量
    js $的扩展写法
    js 获取时区
    export to excel
    使用Sqlserver事务发布实现数据同步(zhuanqian)
    json to entity in api
    automapper demo
    autoMapper的介绍
    Springboot的热部署
  • 原文地址:https://www.cnblogs.com/sunminmin/p/3893966.html
Copyright © 2011-2022 走看看