2018-07-14 iOS 周记录

1,129 阅读4分钟

1、动态库 & 静态库

  • 静态库 : 库中的代码在链接阶段,会把库中的代码copy到执行文件(在iOS中执行文件Mach-O),当我们的程序运行的时候这个执行文件是会被加载到内存中,文件可以在我们的app文件夹中查到。你引用这个静态库几次就会被copy到执行文件中几次。
  • 动态库 : 在iOS中一般是framework,但是我们在创建framework的时候我们也可以在设置界面将framework设置成静态库。动态库的代码并不会加入到Mach-O文件中,framework在文件中只占了一行引用,在运行Mach-O文件的时候,在运行到引入动态库的时候,系统才会去把framework加载进行。
    设置动态库或者静态库

2、胖二进制文件

  • 胖二进制文件:包含多种架构的二进制文件。架构简单点就是CPU的指令集,有的CPU是64位,有的是32位的。所以PC上会有i386 x86_64,iOS手机有arm64(64位的处理器,从iPhone5s开始)armv7(iphone4)armv7s(iPhone5,5c)。因此胖二进制文件可以很方便的在不同的架构上运行。但是这样会导致二进制文件比较大,所以叫做胖二进制文件。这种文件的出现也历史的原因,以前mac用的是ppc架构,之后要迁移到inter上,所以才会出来这种文件。这也导致mac系统的扩展性。据说mac电脑可能会更换CPU使用自己的A系列的处理器。在这种情况下,其实很好迁移。

  • 命令:lipo,大家可以上网查查这个命令,我在这里简单的介绍一下。lipo中文含义脂肪很形象,因为他就是处理胖二进文件的。两个简单常用的命令:

    lipo -info file: 查看文件的包含的架构。

    lipo -create file1 file2 file3:创建一个胖二进制个文件,file1是一种架构的二进制文件如i386,file2是x86_64架构的二进制文件。可以创建一个包含这两种文件的file3文件。

3、动态库与胖二进制

  • 在我们编译framework的时候如果我们选择的是模拟器,那么我们编译的可执行文件就是包含pc架构的二进制文件,i386 x86_64。如果选择的是真机或者Generic iOS Device 编译的二进制文件是iOS架构的。如果想要让这个framework既可以在在真机和模拟器上运行那么可以利用lipo -create来把这个文件整合在一起。

  • 架构的设置

    Architecutres:架构的类型,默认值是$(ARCHS_STANDARD),系统会根据你选择的模拟器或者电脑来编译出二进制文件的架构。如果是模拟器就是以你的电脑为主,如果你的电脑是x84_64,那么编译出来的二进制文件是x86_64如果是i386那么二进制个就是i386。如果运行的是手机,那么二进制文件就是你当前手机的架构,如果是iPhone6,那么就是arm64。你可以在这个选项中添加上你想添加的架构,那么就可以编译出来你加的架构了。但是真机编译的只能是真机的哪几种选项。

    Build Active Archtecture Only:我们上面设置的架构是否有效,Yes表示设置无效,NO 表示设置有效。

    Valid Architecture :表示的是你的项目所支持的处理器架构列表,是一个大的集合,而Architectures表示的是你的项目编译的时候最终生成的二进制文件包含的处理器架构集合。当然如果你的Architectures超出了Valid Architectures的范围,取这两个的交集。

    架构是向下兼容的,arm7s可以运行arm7的二进制文件

4、动态库使用方法

  • 代码
    // 打开framework,参数1:framework路径 参数2:打开模式 RTLD_NOW: 立即打开 RTLD_LAZY: 懒加载
    void *handle = dlopen(libPath.UTF8String, RTLD_NOW);
    if (!handle) {
        NSLog(@"Error: cannot find <%@>", libPath);
        return;
    }
    //利用runtime进行加载类
    NSString *className = [NSString stringWithFormat:@"Test"];
    Class class = NSClassFromString(className);
    if (class == nil) {
        NSLog(@"Error: cannot find class %@", className);
        dlclose(handle);
        return;
    }
    [class performSelector:@selector(run)];
    //关闭framework
    dlclose(handle);
  • 问题

      为什么dlopen打开失败?
      1、framework签名和host app签名的team 不一致
      2、架构不匹配
    

5、user-define