【转】 iOS 开发之静态库.a和动态库详解 -- 不错

原文网址:http://blog.csdn.net/lxl_815520/article/details/52154331

一, 简单介绍

1.什么是库

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

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

   * 开源库

     公开源代码,能看到具体实现

     比如 SDWebImage 、 AFNetworking

   * 闭源库

     不公开源代码,是经过编译后的二进制文件,看不到具体实现

     比如 静态库 、动态库

2.关于静态库和动态库

    1>静态库和动态库的存在形式

       *  静态库: .a 和 .framework

       *  动态库: .dylib 和 .framework

    2>静态库和动态库在使用上的区别

       *  静态库:链接时,静态库会被完整地复制到可执行文件中, 被多次使用就有多份冗余拷贝

       *  动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次(共享),多个程序共用,节省内存

    注意:* 项目中如果使用了自制的动态库,不能被上传到 AppStore. 

           * 系统直接提供给我们的framework都是动态库.

   3>.a和.framework的区别:

      * 一般来说共享库文件都是使用的静态库。而静态库又分.a文件和.framework文件。

      * .framework实际上是一种打包方式,它将头文件,二进制文件和资源文件打包到一起。

      *.a文件是一个纯二进制文件,它必须配合头文件使用。因为使用.a文件一定要同时导入头文件,相比.framework更麻烦一点点,所以更推荐使用.framework。

   4>静态库文件的版本(4种)

       *  真机-Debug版本

      *  真机-Release版本

      *  模拟器-Debug版本

      *  模拟器-Release版本

     Debug(调试)版本:

        * 含完整的符号信息,以方便调试

        * 不会对代码进行优化

     Release(发布)版本:

        *  不会包含完整的符号信息

        *  执行代码是进行过优化的

        *  大小会比Debug版本的略小

        * 在执行速度方面,Release版本会更快些(但不意味着会有显著的提升)

    注意:所以我们一般开发中都打包Release(发布)版本,提供外界

   5>设备的CPU架构简介

        *  模拟器:

            * 4s~5 : i386

            * 5s~6plus : x86_64

        *  真机:

            * 3gs~4s : armv7

            * 5~5c : armv7s (静态库只要支持了armv7,就可以跑在armv7s的架构上)

            * 5s~6plus : arm64

二,制作静态库

  创建.a静态库

     第一步、新建工程。一般使用工程名就使用库的名称,比如我这里用MethodLib来创建静态库,我的工程名就取名为MethodLib,创建的.a静态库就是MethodLib.a。

                                                      

     第二步删除自动生成的文件  替换成我们需要的文件(也可以不删除,直接使用自动生成的文件)。

      第三步创建静态文件

                                                                                                 

     第四步、暴露头文件

          方式一:

          将头文件添加到Copy Files中去:

              

                                                                  

             方式二:

                                                               

                                                 

     第五步、编译静态库

           注意:需要修改Build Settings中的 Build Active Architecture Only以满足运行不同CPU环境的模拟器。将此设置为NO。

                * 如果我们选择的是NO,那么则会适配所有的机型,当然了编译后的包的大小会有点大。

                   * 如果我们选择YES,那么编译的包只会适应当前机型以及版本低的机型,当我们用高于这个手机型号的机型时可能不能用。

           

                                                   修改Build Settings(一).png

             在不同编译环境下编译会生成四种静态库,debug模拟器,debug真机,release模拟器,release真机,我们需要将运行环境调至不同的状态并生成如上四种形式的静态库。这里只以一种情况为例:

     * 设置是Debug还是release

        选择Edit Scheme--> Buid Configuration设置为release

                                                 设置是Debug还是release(一).png

                                                 设置是Debug还是release(二).png

      *  设置模拟器还是真机

         就是设置模拟器还是真机,因为之前我们将只编译当前环境设置为NO,所以编译出来的静态库会支持各种CPU环境。

                      

                                         设置模拟器还是真机.png

      *   按住 command+b 编译啊!(分别在模拟器和真机的环境下编译才能生成所对应环境的静态库)

         你会发现你的静态库文件从红色变成了黑色,这就是编译完成了啊。可以 show in finder 查看文件所在位置。

                                          show in finder.png

       

      * 可以查看打包好的静态库

            

           你会看到如下四个目录,这个就成功啦

     第六步、合并静态库(真机+模拟器)

            * 真机和模拟器的静态库,是不一样的,不能同时适用在真机和模拟器上,但要满足这要求的话,要对编译好的两个静态库进行合并
               合并好坏:
                 好:开发过程中既可以在真机上调试,也可以在模拟器上调试
                 坏:如果静态库太大,合并打包后,会非常大,因此很多第三方的静态库的.a是区分版本的
            * 合并产生新的静态库(终端操作)

               lipo -create 静态文件1路径 静态文件2路径 -output 输出最终文件的目的路径

              具体的步骤:

                 * 在终端输入:lipo  -create 
                 * 将release-iphonesimulator下的.a拖进终端,输入一个空格;
                 * 继续将release-iphoneos 下.a 拖进终端,输入空格;

                 * 继续输入:-output ,打个空格;
                 * 输入合并后的.a所要放的文件路径(假如放在桌面:我的桌面路径为:/Users/admin/Desktop/StaticLibaray.a (可以自己定义.a文件的名字) ),回车,在相应的文件下即可生成一个.a,该.a即是合并后的.a

     第七步、使用静态库

            例如: 在你的要使用太静态库的项目中导入MethodLib.a文件和include文件夹中的相应的所有.h头文件 即可使用

            

     注意点:

             * 记得把要暴漏的头文件放到指定位置
             * 如果源文件中包含类别(category),则需要在使用的时候在Other linker Flags里面添加-Objc的标志,它的作用是把静态库中的所有和对象相关的文件都加载进来。                 否则链接器无法把原有方法和类别整合起来。在64位系统中则需要使用-all_load来加载所有文件。

             * 文件大小.a文件的体积(一般情况下)
                  * 真机用的.a > 模拟器用的.a
                  * 所合成.a == 真机用的.a + 模拟器用的.a

             * 关于静态库对CPU架构的支持,首先了解iOS设备CPU架构方面的知识,ARM是微处理器行业的一家知名企业,arm处理器以体积小和高性能的优势在嵌入式设备中广                 泛使用,几乎所有手机都是使用它的。

                  * 模拟器:iphone4s~5 : i386 iphone5s~6plus : x86_64
                  * 真机:iphone3gs~4s : armv7  iphone5~5c : armv7s (静态库只要支持了armv7,就可以跑在armv7s的架构上) iphone5s~6plus : arm64,armv6, armv7, 

                             armv7s是ARM CPU的不同指令集,原则是向下兼容的。

                           例如iPhone4S CPU支持armv7, 但它同时兼容armv6,只是使用armv6指令可能无法充分发挥它的特性。
             * 查看静态库.a对处理器架构的支持,先cd到.a文件的路径下,命令行输入:lipo -info xxxxx.a
 
             * 如果库中还包含了一些资源文件(如图片等),那么资源文件也应该放在上面的文件夹中

  创建.framework静态库

     第一步、新建工程并选择默认Target为Cocoa Touch Framework, 如图:

               

     第二步、给你的工程命名为MJRefresh,生成的静态库将以标准的名称格式出现.即MJRefresh.framework

               

     第三部、项目自动创建设置开放的头文件和存放资源的Bundle文件,可以看到一个红色的MJRefresh.framework空的静态库

   

     第四步、删除自动生成的MJRefresh.h文件

                          

     第五步、导入MJRefresh框架中的所有文件,应该暴露出来的.h文件默认都在Project下         

              

     第六步、.framework中有些类可能是一些私有的辅助工具,不需要使用者看到,在这里只需要把开放出去的类放到Public下, 如图

                         

     第七步、然后选择模拟器和Debug模式,编译一下,Command + B,此时,虽然看到MJRefresh.framework仍为红色,其实已经生成能在模拟器上运行的.framework静态库,进入MJRefresh.framework目录文件下,以及使用终端可以看到生成的静态库。

选中静态库文件,获取绝对路径如下

 

在目录下可以看到生成的静态库

 

     第八步、再选择真机,设置Release模式,编译一下,Command + B,此时,虽然看到MJRefresh.framework变成黑色,生成能在真机上运行的静态库文件。

在目录下以看到生成的静态库

     第九步、我们随意选择一个静态库,点进去看这个库文件中的具体内容,可以看到一个MJRefresh可执行二进制的文件,资源MJRefresh.bundle,暴露出去的头文件Headers等

     第十步、下面一步就是合并了,生成模拟器和真机环境下通用的二进制可执行文件MJRefresh,生成后看一下这个可执行文件使用的微处理器架构有哪些

                  

     第十一步、好了,合作完成,剩下的就是如何使用这个.framework静态库了。

      (1)我们可以随意选择一个生成的MJRefresh.framework,拷贝一下到桌面

     

       (2)然后再将合并后生成的可执二进制文件MJRefresh拷贝一下,粘贴到桌面上这个MJRefresh.framework文件中,替换里面的MJRefresh,生成一个完成的静态库。

      (3)打开MJRefresh.framework/Modules/module.modulemap文件,可以看到暴露的MJRefrsh.h文件被放在umbrella雨伞下保护起来了,所以我们需要将其他的所有暴露的.h文件放到MJRefresh.h文件中保护起来,不然会出现警告

     (4)我们以为此时大功告成,可以测试代码了,结果出现如下错误:

为什么会这样的?因为我们做的是静态库,在使用的时候需要额外加一个步骤,要把Framework同时添加到‘Embedded Binaries’中

此时再测试,发现没问题了,大功告成,可喜可贺!

  制作静态库的注意点

  (1)注意
   无论是 .a 静态库还是 .framework 静态库,最终需要的都是:二进制文件 + .h + 其它资源文件
  (2).a 和 .framework 的使用区别
  .a 本身是一个二进制文件,需要配上 .h 和 其它资源文件 才能使用
  .framework 本身已经包含了 .h 和 其它资源文件,可以直接使用
  (3)图片资源的处理
  如果静态库中用到了图片资源,一般都放到一个bundle文件中,bundle名字一般跟 .a 或 .framework 名字一致
  bundle的创建:新建一个文件夹,修改扩展名为 .bundle 即可,右击bundle文件,显示包内容,就可以往bundle文件中放东西
  建议:自己制作的静态库中要用到的图片资源,不建议直接以png的后缀名方式拖到项目中使用,而是推荐使用放到bundle文件中。这样可以避免静态库的图片名和使用静态库的项目中存在的图片产生冲突。
    * 新建一个文件夹,把需要打包的资源图片放在里面
  例如:
   
    * 修改扩展名为 .bundle,敲回车,点击添加。
  例如:
    
   (4)多文件处理
  如果静态库需要暴露出来的 .h 比较多,可以考虑创建一个主头文件(一般 主头文件 和 静态库 同名)
  在主头文件中包含所有其他需要暴露出来的 .h 文件
  使用静态库时,只需要#import 主头文件
  实际上苹果官方就是这么做的,例如:#import <UIKit/UIKit.h>
 (5).framework为什么既是静态库又是动态库
  系统的 .framework 是动态库
  我们自己建立的 .framework 是静态库
 (6) 静态库中包含了Category(分类)
     如果静态库中包含了Category,有时候在使用静态库的工程中会报“方法找不到”的错误(unrecognized selector sent to instance)
     解决方案:在使用静态库的工程中配置Other Linker Flags为-ObjC

原文地址:https://www.cnblogs.com/wi100sh/p/6125952.html