runtime基础、消息转发

来源:互联网 发布:茶叶网络连锁 编辑:程序博客网 时间:2024/06/05 20:29

runtime术语
1、Class、id

#if !OBJC_TYPES_DEFINED/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;/// Represents an instance of a class.struct objc_object {    Class isa  OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;#endif

Class是一个指向objc_class结构体的指针;id是一个指向objc_object结构体的指针;而objc_object中的isa指针指向Class结构

2、objc_class

typedef struct objc_class *Class;struct objc_class {  Class isa                OBJC_ISA_AVAILABILITY; // metaclass#if !__OBJC2__ Class super_class        OBJC2_UNAVAILABLE; // 父类 const char *name         OBJC2_UNAVAILABLE; // 类名 long version             OBJC2_UNAVAILABLE; // 类的版本信息,默认为0,可以通过runtime函数class_setVersion或者class_getVersion进行修改、读取 long info              OBJC2_UNAVAILABLE; // 类信息,供运行时期使用的一些位标识,如CLS_CLASS (0x1L) 表示该类为普通 class,其中包含实例方法和变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法; long instance_size      OBJC2_UNAVAILABLE; // 该类的实例变量大小(包括从父类继承下来的实例变量) struct objc_ivar_list *ivars              OBJC2_UNAVAILABLE; // 该类的成员变量地址列表 struct objc_method_list **methodLists     OBJC2_UNAVAILABLE; // 方法地址列表,与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储实例方法,如CLS_META (0x2L),则存储类方法; struct objc_cache *cache                  OBJC2_UNAVAILABLE; // 缓存最近使用的方法地址,用于提升效率; struct objc_protocol_list *protocols      OBJC2_UNAVAILABLE; // 存储该类声明遵守的协议的列表#endif}/* Use `Class` instead of `struct objc_class *` */

从以上类objc_class的结构可以看出,类和对象的区别是类比对象多了很多特征成员,类也可以看成objc_object,即分别称作类对象和实例对象。

isa: 实例对象objc_object中的isa指针指向的是类结构objc_class,其中存放着普通成员变量与动态方法(“-”开头的方法);而objc_class中的isa指针指向类对应的元类(metaclass),metaclass中存放着static类型的成员变量与static类型的方法(“+”开头的方法).

3、SEL
SEL是selector在OC中的表示类型,selector可以理解为区别方法的ID

typedef struct objc_selector *SEL;objc_selector的定义如下:struct objc_selector {    char *name;        OBJC2_UNAVAILABLE;// 名称    char *types;       OBJC2_UNAVAILABLE;// 类型};

4、IMP

typedef id (*IMP)(id,SEL,……);

IMP是”implementtation”缩写,它是有编译器生成的一个函数指针。当调用一个消息后,IMP决定了最终执行代码的入口。

5、Method代表类中的某个方法的类型

typedef struct objc_method *Method;struct objc_method {    SEL method_name       OBJC2_UNAVAILABLE; // 方法名    char *method_types    OBJC2_UNAVAILABLE; // 方法类型    IMP method_imp        OBJC2_UNAVAILABLE; // 方法实现}

6、Ivar代表类中实例变量的类型

typedef struct objc_ivar *Ivar;struct objc_ivar {    char *ivar_name        OBJC2_UNAVAILABLE; // 变量名    char *ivar_type        OBJC2_UNAVAILABLE; // 变量类型    int ivar_offset        OBJC2_UNAVAILABLE; // 基地址偏移字节#ifdef __LP64__    int space              OBJC2_UNAVAILABLE; // 占用空间#endif}

7、objc_property_t属性

typedef struct objc_property *objc_property_t;

objc_property是内置的类型,与之关联的还有一个objc_property_attribute_t,它是属性的attribute,也就是其实是对属性的详细描述,包括属性名称、属性编码类型、原子类型/非原子类型等。它的定义如下:

typedef struct {    const char *name; // 名称    const char *value;  // 值(通常是空的)} objc_property_attribute_t;

8、Catagory
这个就是我们平时所说的类别了,很熟悉吧。它可以动态的为已存在的类添加新的方法。
它的定义如下:

typedef struct objc_category *Category;struct objc_category {    char *category_name        OBJC2_UNAVAILABLE; // 类别名称    char *class_name           OBJC2_UNAVAILABLE; // 类名    struct objc_method_list *instance_methods  OBJC2_UNAVAILABLE; // 实例方法列表    struct objc_method_list *class_methods        OBJC2_UNAVAILABLE; // 类方法列表    struct objc_protocol_list *protocols          OBJC2_UNAVAILABLE; // 协议列表}

常见方法

1、获取属性的列表—-class_copyPropertyList()

objc_property_t *propertyList = class_copyPropetyList([self class],&count);

2、获取方法列表-class_copyMethodList()

Method *methodList = class_copyMethodList([self class],&count);

3、获取成员变量列表-class_copyIvarList()

Ivar  *ivarList = class_copyIvarList([self class],&count);

4、获取协议列表-class_copyProtocolList

__unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class],&count);

5、获取方法-objc_getClass
现有一个Person类,和person创建的xiaoming对象,有test1和test2两个方法

获得类方法Class PersonClass = object_getClass([Person class]);SEL oriSEL = @selector(test1);Method oriMethod = class_getInstanceMethod(xiaomingClass, oriSEL);获得实例方法Class PersonClass = object_getClass([xiaoming class]);SEL oriSEL = @selector(test2);Method cusMethod = class_getInstanceMethod(xiaomingClass, oriSEL);

6、添加方法

BOOL adduce = class_addMethod(xiaomingClass,oriSEL,method_getImplementation(cusMethod),method_getTypeEncoding(cusMethod));

7、替换原方法实现

class_replaceMethod(toolClass,cusSel,Method_getImplementation(oriMethod),method_getTypeEncoding(oriMethod));

8、交换两个方法

method_exchangeImplementation(oriMethod,cusMethod);

常见作用

动态添加对象的成员变量和方法
动态交换两个方法的实现
拦截并替换方法
在方法上增加额外的功能
实现NSCoding的自动归档和解档
实现字典转模型的自动转换

runtime的消息传递
(1)发送消息涉及的函数
在OC程序中向一个对象发送消息,编译时会转换成runtime的objc_msgSend函数的调用,
例如某实例变量receiver实现oneMethod的函数调用

[receiver oneMethod];

会转换成类似一下的代码

objc_msgSend[receiver,selector];

实际上Runtime会根据类型自动转换成下列的某一函数
objc_msgSend:普通的消息都会通过该函数发送
objc_msgSend_stret:消息中有返回值(不是简单值)时,通过该函数发送消息,并接受返回值
objc_msgSendSuper:和objc_msgSend类似,把消息发送给父类的实例
objc_msgSendSuper_stret和objc_msgSend_stret类似:消息发型给父类的实例并接受返回值
(2)objc_msgSend函数的调用过程
第一:检查这个selector是不是要忽略的
第二:检查这个target是不是nil对象,nil对象发送的任意消息都会被忽略
第三:当调用实例方法时,它会根据自身的isa指针指向的类(class)的methodLists中查找该方法,如果找不到则会通过class的super_class指针找到父类,进而在父类中methodLists中查找该方法,如果还是找不到,则继续通过父类的super_class指针找到父类的父类,直到根类
当调用类方法时,它会通过自己的isa指针找到metaclass,并在metaclass中的methodLists中查找该方法,如果找不到则会通过metaclass中的super_calss指针找到其父类,然后在父类的methodLists中查找该方法,如果还是找不到,则继续通过父类的super_class指针找到父类的父类,直到根类metaclass
第四:如果第三步还是找不到就会进入动态方法解析
这里写图片描述

*通过resolveInstanceMethod:方法决定是否动态添加方法。如果返回YES,则通过class_addMethod动态添加方法,使消息得到处理;如果返回NO,则进入下一步。
*这一步进入forwordingTargetForSelector:方法,用于指定备选对象来响应这个selector(不能指定self),如果返回某个对象则会调用该对象的方法,结束;如果返回nil,则进入下一步
*这一步会调用methodSignatureForSelector:方法签名,如果返回nil,则消息无法处理;如果返回methodSignature,则调用forwordInvocation:方法,我们可以通过anInvocation对象修改实现方法、修改响应对象等,如果调用成功,则结束。如果失败,进入doseNotRecognizeSelector方法,如果没有实现该方法,就会crash

学习时的Demo:https://github.com/onebutterflyW/runtime
参考网址:https://www.ianisme.com/ios/2019.html
http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/#SEL

0 0
原创粉丝点击