runtime基础、消息转发

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
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值