浅谈Runtime(一)

2018-05-06  本文已影响0人  小宇pod

如有不同看法,欢迎讨论。

一. RunTime是什么

runtime(简称运行时),是一套 纯C(C和汇编写的) 的API。而 OC 就是 运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
这里要提的一点是,在C中的是无法调用未实现的函数的,否则会报错;但是在OC中,只要声明了方法就可以调用,只有在程序运行的时候才会报错,这一点也反映了OC的动态特性。

二. 动态特性

关于OC的动态特性主要体现在以下三个方面:1.动态类型:即运行时再决定对象类型。比如我们常见的id类型,任何对象都可以被id类型的指针所指,在运行时再确定具体类型;2.动态绑定:即在运行时决定该对象所拥有的对象及方法,一个例子就是在编写代码的时候,一个只声明未实现的方法依然可以被调用,但在运行时才会报错;3:动态载入:在运行时决定需要加载哪一部分资源,同样一个常见的例子就是通过不同机型决定加载@2x的图片还是@3x的图片。

三. Class的结构

首先是通过终端输入

clang -rewrite-objc MyClass.m
则会出现一个.cpp的C++编译的文件 WechatIMG20.jpeg

里边的代码很多,全局搜索

typedef struct objc_class *Class;

你会看到

typedef struct objc_class *Class;
struct objc_object {
    Class isa __attribute__((deprecated));
};

即Class其实是一个objc_class类型的结构体,而objc_object是一个包含着isa指针的结构体,在runtime.h中我们可以看到objc_class的定义:

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

其中具体的变量看英文名大体就能明白具体是干什么的,比如objc_method_list就是这个类所包含的方法列表,objc_ivar_list是成员变量列表,等等等等。同样我们也能通过Runtime取到这个类的属性,方法等;或者在运行中给类绑定属性,方法。

四. 消息发送流程

在这里我们已经知道,OC是一门动态语言,那么就有一个问题出来了,消息是怎么发送的,换言之当我们调用这个类的方法时发生了什么?
定义一个MyClass类,然后声明一个方法

- (void)showName:(NSString *)name;

OC 在向一个对象发送消息时,runtime 库会根据对象的isa指针遍历这个对象的methodLists,如果没找到,会遍历父类的methodLists,最终找到 SEL ,根据 id 和 SEL 确认 IMP(指针函数),在发送消息。如果找不到,则程序崩溃,报常见的unrecognized selector sent to class 0x10bb9b060,即没有找到实现的方法。
任何方法本质上都是向对象发送消息,比如我们常见的

    MyClass *class = [MyClass alloc];

可以用runtime这样写

MyClass *class = ((MyClass * (*) (id, SEL)) objc_msgSend) (objc_getClass("MyClass"), sel_registerName("alloc"));

解释一下(id, SEL)是传入参数类型,也就是说,如果需要调用函数是带参数的,需要增加参数个数,例如:

int str = ((int (*) (id, SEL, int)) objc_msgSend) (objc_getClass("MyClass"), sel_registerName("showInt:"),12);

MyClass * ()是返回的类型,如果方法无返回值则是void ()。
先写到这里,至于Runtime的具体应用和应用场景再开一篇再写。

上一篇下一篇

猜你喜欢

热点阅读