1. app启动到内存加载

2020-09-07  本文已影响0人  算命的李老师
==app启动到Runtime==

例子:

#import <Foundation/Foundation.h>

@interface HelloWorld : NSObject

- (void) sayHello;

@end

@implementation HelloWorld

+ (void) load {
    NSLog(@"Hello World load");
}

- (instancetype) init {
    if(self = [super init]) {
        NSLog(@"Hello World init");
        return self;
    } else
        return nil;
}

- (void) sayHello {
    NSLog(@"Hello World");
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        HelloWorld* helloworld = [HelloWorld new];
        [helloworld sayHello];
    }
    return 0;
}

编译完成后,这个可执行文件,有一个头部,用于表明文件信息:

Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL LIB64     EXECUTE    18       2496   NOUNDEFS DYLDLINK TWOLEVEL PIE

当你执行它,该二进制文件会被读取,操作系统可执行程序加载器会加载该文件,读取该头部,判断是否是一个合法的二进制可执行文件,如果可以执行,则开始文件的 parse (解析)过程,该过程提取 LC (Load Command) 信息。这里会找到应用程序入口信息 LC_MAIN,动态连接器加载器 LC_LOAD_DYLINKER 信息等,如果找到合法的动态连接器,则调用它,将控制权交给它,这时默认的 dyld (动态链接器)会再对二进制文件进行 parse,找到 LC_LOAD_DYLIB ,这里可能有多个。

对于一个最简单的 Cocoa App,至少会有 :
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (offset 24)
/usr/lib/libobjc.A.dylib (offset 24) (ObjC runtime)
/usr/lib/libSystem.B.dylib (offset 24) (C runtime)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (offset 24)

这时 dyld 会加载或映射这些库到地址空间中来,解析符号,初始化库,在初始化的过程中,库可以向 dyld 注册回调函数,runtime 这时即可获取文件中诸如 __objc_classlist __objc_nlclslist __objc_methname 等等信息,用于构建各类关系,为 OC 特性作支撑。

最后,dyld 会找到 LC_MAIN 入口压入初始化参数等,跳转将控制权交与程序本身,这时开始运行。
运行过程中,dyld 负责动态解析符号,比如 [helloworld sayHello] 该调用实际在编译时被替换为 objc_msgSend 然而 objc_msgSend 又在 runtime 里,这样,runtime 也就会时时存在,所有的方法调用,OC 特性的使用都会到 runtime 里。

==Category 在编译过后,是在什么时机与原有的类合并到一起的?==
  • 程序启动后,通过编译之后,Runtime 会进行初始化,调用 _objc_init。
  • 然后会 map_images。
  • 接下来调用 map_images_nolock。
  • 再然后就是 read_images,这个方法会读取所有的类的相关信息。
  • 最后是调用 reMethodizeClass:,这个方法是重新方法化的意思。
  • 在 reMethodizeClass: 方法内部会调用 attachCategories: ,这个方法会传入 Class 和 Category ,会将方法列表,协议列表等与原有的类合并。最后加入到 class_rw_t 结构体
上一篇 下一篇

猜你喜欢

热点阅读