runtime之OC消息派发与消息转发:

一:OC对象,类及元类的理解:

1):OC对象分析

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;

每一个OC对象均包含以下信息:

isa:指向元类的objc_class的结构体指针,元类中保存有类对象的类方法;

super_class:指向父类的objc_class的结构体指针,可以通过父类找到变量与方法;

name:类名

version:类的版本信息

info:类信息,供运行期使用的标识

instance_size:类的实例变量的大小

objc_ivar_list:成员变量的链表(objc_ivar:类的成员变量(名称,类型,偏移字节,占用空间))

objc_method_list:方法链表(objc_method:SEL方法选择器,HASH后的值,IMP则是指向实现函数的指针)

objc_cache:对象使用过(缓存)的方法链表

objc_protocol_list:协议链表

 

2):元类分析:

a):元类定义:元类就是类对象的类,每一个类对象均有一个元类。

b):元类用途:

当调用实例方法,也就是给对象发送消息时,实际上是在对象所属类的方法链表中查找;

当调用类方法,也就是给类发送消息时,实际上是在类所属元类的方法链表中查找;

c):元类的理解:

实例对象的isa指向该实例对象的类,类对象的isa指向该类对象的元类,元类对象的isa指向根元类,根元类的isa指针指向自身。

 

二:OC中消息派发分析:

1):方法调用包含三要素:执行方法的对象,调用的方法以及方法所需的参数

2):方法的执行包含编译与运行两部分,因为OC是动态语言,所以OC在编译时,并不决定方法调用的三要素;而是在运行时,才决定方法执行的三要素。(静态语言,则是在编译期间就决定方法执行的三要素,且不能更改)

3):OC方法调用的实质是消息派发

以[person work]为例,本质上是执行objc_msgSend(id _Nullable self, SEL _Nonnull op, ...),其中self是执行方法的对象,SEL则是要执行的方法,...则是方法所需的参数。

调用实例方法:(以[person work]为例)

1:通过person对象的isa指针找到Person类

2:在Person类的缓存方法链表objc_cache中查找work方法(这时的work方法为实例方法)

3:若没有找到,则在Person类的方法链表objc_method_list中找到需要执行的work方法

4:若没有找到,则通过Person类的super_class指针查找Person类的父类,重复执行步骤2,3

5:若最终找到work方法,则通过IMP指针找到实现函数执行;若最终没有找到work方法,则进入OC的消息转发机制。

调用类方法:以[Person growUp]为例)

1:通过Person类的isa指针找到Person的元类

2:在元类的缓存方法链表objc_cache中查找work方法(这时的work方法为类方法)

3:若没有找到,则在元类的方法链表objc_method_list中查找work方法

4:若没有找到,则通过元类的isa指针找到根元类,重复执行步骤2,3

5:若最终没有找到work方法,则进入OC的消息转发机制

 

三:OC中的消息转发分析:(所有进入消息转发机制中的消息,均为未知消息)

当在消息派发机制中,没有找到要执行的方法,则会进入OC中的消息转发机制。

OC中的消息转发机制分为三步:动态方法绑定,备用接收者以及完整消息转发。

1):动态方法解析:

(当要执行的方法未实现时,可以通过动态方法解析,来动态的添加该方法及其实现)

接收者需要重写NSObject的resolveInstanceMethod:方法:

+ (BOOL)resolveInstanceMethod:(SEL)sel {

    //系统注册该方法

    SEL systemSel = sel_registerName(sel_getName(sel));

    //接收者添加该方法,及其实现

    class_addMethod(self, systemSel, (IMP)dynamicMethodIMP, "v@:");

    return [super resolveInstanceMethod:systemSel];

}

首先,需向系统注册要实现的方法,然后,接收者需要添加方法实现,最后,实现动态方法解析;

2):备用接收者:

(当执行未知消息的接收者,查找不到要执行的方法,可以替换执行过未知消息的接收者作为备用接收者)

接收者需要重写forwardingTargetForSelector:方法:

- (id)forwardingTargetForSelector:(SEL)aSelector {

    return [[Person alloc] init];//Person:实现aSelector方法的类

}

备用接收者不能为self,否则会出现死循环;也不能为nil,否则会进入消息转发第三步;

3):完整消息转发(NSInvocation)

(NSInvocation:完整消息的载体,记录一个消息的接收者,方法名,参数类型,参数等等,类似Method的结构体;

    NSMethodSignature:方法签名,记录一个方法参数及返回值的类型(用于初始化NSInvocation类);

当动态添加方法及实现,替换备用接收者都不能处理未知消息时,只能进行完整消息的转发(forwardInvocation)。

接收者需要重写methodSignatureForSelector:及forwardInvocation:方法

//生成NSMethodSignature,进而用于初始化NSInvocation

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

    NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];//获取aSelector的方法签名

    if (!methodSignature) {//若存在,直接返回;若不存在,则instanceMethodSignatureForSelector:获取

        if ([Person instancesRespondToSelector:aSelector]) {

            methodSignature = [Person instanceMethodSignatureForSelector:aSelector];

        }

    }

    return methodSignature;

}

//转发未知消息

- (void)forwardInvocation:(NSInvocation *)anInvocation {

    if ([Person instancesRespondToSelector:anInvocation.selector]) {

        [anInvocation invokeWithTarget:[[Person alloc] init]];//替换接收者,调用未知信息

    }

}

 

四:OC消息派发,消息转发理解

1):在消息转发的步骤2,3中,均是替换未知消息的接收者,达到备用接收者响应未知消息的目的。

因此,我们可以将一些未知消息的处理放在某一个类中,当其他类需要响应这些未知消息时,可以替换备用接收者,响应这些未知消息,从而达到一个OC对象,继承不同类的方法。(OC的“多重继承”)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值