第1年7月12日 iOS运行加载动态库

1.

在运行时加载动态库,是指不需要在工程中引入动态库,作为替代,在代码中使用dlopen()这个函数来加载动态库,在调用完成之后,需要调用相同次数的dlclose()函数来关闭动态库。

除了dlopen()和dlclose()以外,另外还有一个dlsym()函数来根据传入的symbol获取对应数据或函数的地址。在本例中,会使用runtime机制来代替dlsym()函数。(dlsym()一般是在c或c++中使用)

1.创建新工程DylibDemo-Runtime,添加被调用库的头文件LibPerson.h(这里不需要添加LibPersonFramework.framework)


2.在main.h文件中加载和调用LibPersonFramework.framework

void loadWhenRunTime(){

    // Open the library.

    NSString *bundlePath = [[NSBundle mainBundle]pathForResource:@"LibPersonFramework" ofType:nil];

    void* lib_handle = dlopen([bundlePath UTF8String], RTLD_LOCAL);

    if (!lib_handle) {

        NSLog(@"[%s] main: Unable to open library: %s\n",

              __FILE__, dlerror());

        exit(EXIT_FAILURE);

    }

    Class class_person = objc_getClass("LibPerson");

    LibPerson *person = [class_person new];

    person.name = @"wang";

    [person watch];

    [person eat];

    // Close the library.

    if (dlclose(lib_handle) != 0) {

        NSLog(@"[%s] Unable to close library: %s\n",

              __FILE__, dlerror());

        exit(EXIT_FAILURE);

    }

}

dlopen()函数需要传入两个参数path和mode,path表示动态库的mach-o文件的路径,mode中可以包含多个标识符,比如RTLD_LAZY和RTLD_NOW表示动态库中的symbol什么时候被加载,RTLD_GLOBAL和RTLD_LOCAL表示symbol的可见性。(详情可通过终端命令man dlopen查看)

上述代码中,path指定动态库是在生成的app包中,文件名为LibPersonFramework;mode的值是RTLD_LOCAL,表示在使用dlsym()函数时,只能通过dlopen()函数返回的handle来获取传入的symbol的地址,由于在例中并不会使用dlsym()函数,所以大可不必关注这个值。

另外,在上述代码中还有一点需要注意的,在创建LibPerson类的对象时,不能直接使用LibPerson *person = [LibPerson new],如果这样做,程序会报如下编译错误:

Undefined symbols for architecture arm64:

  "_OBJC_CLASS_$_LibPerson", referenced from:

      objc-class-ref in main.o

ld: symbol(s) not found for architecture arm64

 

这是因为在编译时,如果调用了[LibPerson new],编译器会去验证app的mach-o文件以及它依赖的动态库的mach-o文件中是否有这个类的定义。

由于在编译时,程序还没有加载动态库LibPersonFramework,而程序只包含了LIbPerson类的头文件,并没有它对应的.m文件(编译器只会将.m文件编译到最终的mach-o文件中),所以编译器在app的mach-o文件以及它依赖的动态库中找不到LibPerson类的定义,然后编译器就报错了。

从上述代码可以看出,在创建LibPerson类的对象时,程序中其实已经加载了LibPersonFramework,也就是说,在那个时候程序中已经有这个类的定义了。所以,上述代码中使用了下列代码来”欺骗“编译器。

Class class_person = objc_getClass("LibPerson");

  LibPerson *person = [class_person new];

 



https://www.jianshu.com/p/be0c6fe4fba0?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

posted @ 2021-07-12 15:51  lianhuaren  阅读(450)  评论(0编辑  收藏  举报