美文网首页
消息动态决议

消息动态决议

作者: MrHardy | 来源:发表于2021-07-02 17:42 被阅读0次

我们先从lookUpImpOrForward看起

  • realizeAndInitializeIfNeeded_locked jump


  • initializeAndLeaveLocked jump


  • initializeAndMaybeRelock jump


  • initializeNonMetaClass jump



    [图片上传失败...(image-122663-1625218937103)]

  • callInitialize jump



    callInitialize 会把当前的class的initialize进行系统调用

二分法查找


举例现在1-8共8个方法,count=8,假设现在正确的方法在7号位置,当前0号位置开始,开始右移

base + (count >> 1) = 0 + (8 >> 1) = 1000 >> 1 = 0100 = 4 //当前位置  
base = probe + 1 = 4 + 1 = 5;//当前位置
base = probe + 1 = 5 + 1 = 6;//当前位置 
base = probe + 1 = 5 + 1 = 7;//当前位置  

count -- = 8 - 1 = 7;
count = 7 >> 1 = 0111 >> 1 = 0011 = 3
count = 6 >> 1 = 0011 >> 1 = 0001 = 1
count -- = 3 - 1 = 2;
count = 2 >> 1 = 0010 >> 1 = 0001 = 1
1 >> 1 = 0001 >> 1 = 0
  • 查找流程:自己的类->找父类->缓存查找->lookupimp->父类的缓存(cache)

坑点


1、对象调用一个类方法,是可以成功的,只要在NSObject里处理,在分类添加,根本原因是isa的走位图。

不写m文件里的实现,会报错如下


  • _objc_msgForward_impcache
  • __objc_forward_handler
//重点代码
  _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
                "(no message forward handler is installed)", 
                class_isMetaClass(object_getClass(self)) ? '+' : '-', 
                object_getClassName(self), sel_getName(sel), self);

动态方法决议

// 单例方法只会执行一次
//3 & 2 = 0011 & 0010 = 0010 = 2
//2 & 2 = 0 = behavior
if (slowpath(behavior & LOOKUP_RESOLVER)) {
        behavior ^= LOOKUP_RESOLVER;
        return resolveMethod_locked(inst, sel, cls, behavior);
    }

再次动态默认赋值


behavior 来源


当方法没有写实现,缓存查找及慢速的递归流程查找后,还是没找到,会导致崩溃!!!


再给最后一个机会,重新开始查找lookUpImpOrForwardTryCache,返回imp
return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);


#if CONFIG_USE_PREOPT_CACHES
    if (fastpath(cls->cache.isConstantOptimizedCache(/* strict */true))) {
        imp = cache_getImp(cls->cache.preoptFallbackClass(), sel);
    }
#endif
 if (slowpath(imp == NULL)) {
        return lookUpImpOrForward(inst, sel, cls, behavior);
    }
   
   再次执行lookUpImpOrForward
   满足下面的条件,可以再找一次
   //判断是不是元类
       if (! cls->isMetaClass()) {
        // try [cls resolveInstanceMethod:sel]
        resolveInstanceMethod(inst, sel, cls);
    } 
    else {
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        resolveClassMethod(inst, sel, cls);
        if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
            resolveInstanceMethod(inst, sel, cls);
        }
    }
  • resolveInstanceMethod jump



 - resolve_sel 系统发送这个消息
执行 IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
在这里执行了两次TryCache
//只要使用了下面的方法 SEL resolve_sel = @selector(resolveInstanceMethod:), 就不会报错
 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    bool resolved = msg(cls, resolve_sel, sel);

.m添加如下代码


在程序报错之前,走了上面定义的方法,输出如下


+ (BOOL)resolveInstanceMethod:(SEL)sel{
    
    if (sel == @selector(sayNB)) {
        
        IMP teacherSayImp = class_getMethodImplementation(self, @selector(teacherSay));
        
        Method method = class_getInstanceMethod(self, @selector(teacherSay));
        
        const char *type = method_getTypeEncoding(method);
        
        return  class_addMethod(self,sel,teacherSayImp,type);
    }
    
    NSLog(@"resolveInstanceMethod : %@-%@",self,NSStringFromSelector(sel));
 
    return [super resolveInstanceMethod:sel];
    
}

 //替换 输出 
 -[HLTeacher teacherSay]
Program ended with exit code: 0

系统默认实现,系统会帮你兜底。


类方法的动态决议

 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
 bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);

nonmeta 当前元类

resolveClassMethod : HLTeacher-encodeWithOSLogCoder:options:maxLength:
resolveClassMethod : HLTeacher-sayHappy
+[HLTeacher sayHappy]: unrecognized selector sent to class 0x100008508
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[HLTeacher sayHappy]: unrecognized selector sent to class 0x100008508'

resolveClassMethod : HLTeacher-encodeWithOSLogCoder:options:maxLength:
HLTeacher - +[HLTeacher sayHello]

未完待续......

相关文章

  • 消息动态决议

    前言 前面我们分析了消息的查找流程,快速查找流程,慢速查找流程。如果这两种方式都没找到方法的实现,苹果给了两个建议...

  • 消息动态决议

    我们上一章针对[消息的慢速查找](https://www.jianshu.com/p/f03392ffe0b3[h...

  • 消息动态决议

    我们先从lookUpImpOrForward看起 realizeAndInitializeIfNeeded_loc...

  • 消息的动态决议

    当lookupImpOrForward函数从cache和methodTable中找不到对应Method,继续向下执...

  • runtime简单笔记

    动态特性: 动态类型、动态绑定、动态方法决议、动态加载、内省 编译器会把[接收器 消息]形式的对象消息,转换为含有...

  • Runtime — 动态方法决议

    前言 在 消息发送 中,当查不到方法时,会进行动态方法决议,下面我们就来具体分析一下动态方法决议过程中,系统如果操...

  • 九、消息流程之动态决议

    在消息经过慢速查找之后还没有找到,就会走到resolveMethod_locked进行消息动态决议,看一下reso...

  • 消息转发之动态方法决议 & 消息转发

    前言 前面的两篇文章我们已经探索了消息的快速查找和慢速查找的流程。 objc_msgSend 流程之缓存查找[ht...

  • 十、消息流程—动态方法决议 & 消息转发

    主要内容:objc_msgSend的快速查找和慢速查找,都没有找到方法时,苹果给了挽救的机会:一、动态方法决议1....

  • iOS Objective-C 消息的转发

    iOS Objective-C 消息的转发 1.动态方法决议(解析) 在上一篇消息查找的文章中我们在消息查找中没有...

网友评论

      本文标题:消息动态决议

      本文链接:https://www.haomeiwen.com/subject/qzcyultx.html