消息机制

runtime----消息发送机制

objc_msgSend执行流程:
OC中的方法调用,其实都是转换为objc_msgSend函数的调用
objc_msgSend的执行流程可以分为3大阶段:
1.消息发送
2.动态方法解析
3.消息转发

在消息发送阶段就会找到相应方法进行调用,如果没有找到就会进入到动态方法解析阶段,如果这一阶段还没找到就会进入消息转发阶段。

----动态解析过程中进行 动态添加方法----

  • (BOOL)resolveInstanceMethod:(SEL)sel
    {
    if (sel == @selector(test)){
    Method method = class_getInstanceMethod(self,@selector(other));// Method 可以理解为等价于 struct method_t*
    class_addMethod(self,
    sel,
    method_getImplesentation(method),
    method_getTypesEncoding(method)
    );
    return YES;
    }
    return [super resolveInstanceMethod:sel];
    }

void other(id self,SEL _cmd)
{
NSLog("%@–%s–%s", self, sel_getName(_cmd), func);
}

  • (BOOL)resolveInstanceMethod:(SEL)sel
    {
    if (sel == @selector(test)){
    class_addMethod(self, sel, (IMP)other, “v16@0:8”);
    return YES;
    }
    return [super resolveInstanceMethod:sel];
    }

问题:讲一下OC的消息机制
答:1.OC中的方法调用其实都是转成了objc_msgSend函数的调用,给receiver(方法调用者也就是消息的接收者)发送了一条消息(selector方法名)
2.objc_msgSend底层有3大阶段:消息发送(当前类、父类中查找)、动态方法解析、消息转发
第一阶段消息发送如果在当前类或者父类找到了该方法就执行,找不到就进入第二阶段动态方法解析,如果在第二阶段又没有做任何处理,就进入第三阶段消息转发,如果第三阶段消息转发还是找不到该方法也没有做处理,就会报错,报方法找不到的错误。

问题:消息转发机制流程
解析:参考上图

问题:什么事Runtime?平时项目中有用过吗?
解析:

@interface MJPerson:NSObject
@property (assign ,nomatomic) int age;
@end
@implementation MJPerson
@dynamic age;
@end
注:@dynamic是告诉编译器不要自动生成getter和setter方法的实现,等到运行时再添加方法实现。


下面主要考察的是super、kindofclass、memberofclass

答案是:左边打印结果从上到下是:MJStudent/MJStudent/MJPerson/MJPerson
右边打印结果从上到下是:1、0、0、0(1代表返回的是YES)
[super xxx方法] 的底层实现:
1.消息接收者仍然是子类对象
2.从父类开始查找方法的实现
方法调用者就是消息接收者,receiver
[self xxx方法];
是先根据isa指针找到自己类然后从类方法里找有没有这个方法,
如果没有再通过isa指针找到父类,在父类的方法里找有没有这个方法,没有再往上找。
[super xxx方法];
是利用消息机制直接把父类传过去,直接从父类的方法里找有没有这个方法,没有再往上找。
总结:[self xxx方法];[super xxx方法];这两种调用方式的消息接收者都是当前类,也就是self

isMemberOfClass: 和 isKindOfClass: 的底层实现:

  • (BOOL)isMemberOfClass:(Class)cls{//类方法
    return object_getClass((id)self) == cls;
    }
  • (BOOL)isMemberOfClass:(Class)cls{//对象方法
    return [self class] == cls;
    }
  • (BOOL)isKindOfClass:(Class)cls{
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass){
    if (tcls == cls) return YES;
    }
    return NO;
    }
  • (BOOL)isKindOfClass:(Class)cls{
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass){
    if (tcls == cls) return YES;
    }
    return NO;
    }
    例如类:MJPerson *person;那么MJPerson是类对象,person是实例对象。
  • [实例对象 isMemberOfClass:xxx] 意思是:左边的和右边的一样
  • [实例对象 isKindOfClass:xxx] 意思是:左边的和右边的一样,或者左边的父类和右边一样。
  • [类对象 isMemberOfClass:xxx] 意思是:左边’xxx的元类’和右边’xxx’一样
  • [类对象 isKindOfClass:xxx] 意思是:左边’xxx的元类’和右边’xxx’一样,或者’xxx的元类’的父类和右边’xxx’一样。
    object_getClass(xxx) 意思是:返回xxx的元类,注意元类和类不相等。另外当通过isa一层层向上找方法时,找到最顶部的元类后再往上找,那就跑到了NSObject类里面去了,也就是说最顶部的元类再调用“object_getClass()”这个方法时返回的就是NSObject这个类了

常见的‘找不到方法’崩溃的解决办法:想要解决找不到方法报错的问题,可以在.m里实现下面两个方法,这样如果再出现找不到方法的问题就不会报错了,而是打印出这个方法名
#import “MJPerson.h”
@implementation MJPerson

  • (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
    //本来能调用的方法
    if ([self respondsToSelector:aSelector]){
    return [super methodSignatureForSelector:aSelector];
    }
    //找不到的方法
    return [NSMethodSignature signatureWithObjcTypes:“v16@0:8”];
    }

  • (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    NSLog(@“找不到%@方法”,NSStringFromSelector(anInvocation.selector));
    }
    @end

欢迎各位朋友进行询问沟通交流,有不清楚的或者不明白的欢迎提问交流

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值