iOS 消息查找流程 objc_send

1.OC调用方法的本质

  我们都知道或听过,比如 在OC里面 写 [preson sayNB] 那么底层实际走的是objc_msgSend 的API :objc_msgSend(person, @selector(sayNB))

这部分源码在可以在苹果官方开源的objc里面查看。如何你想去了解 可以看看objc-msg-arm64.s ;这是个纯汇编代码;也就是说objc_msgSend是用汇编来实现;为什么要用汇编,因为汇编快!

2.汇编快速查找cache

里面大概主流程如下:

先进入 ENTRY _objc_msgSend

1.cmp p0, #0 // nil check and tagged pointer check  判断p0(消息接收者 就是person)是否存在;存在就往下走

2.GetClassFromIsa_p16 p13, 1, x0 // p16 = class,    这里可以拿到 isa和class

3.CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached

3.1 LLookupStart (CACHE_MASK_STORAGE_HIGH_16 为真机架构流程)

 //获取缓存cache

    ldr p11, [x16, #CACHE] // p11 = mask|buckets

// p11的位置是否为0 不为0就跑LLookupPreopt

tbnz p11, #0, LLookupPreopt\Function

and p10, p11, #0x0000ffffffffffff // p10 = buckets

// p1 sel>>7  因为cache 存入时是 value  ^= value >>7  就是一样的操作

eor p12, p1, p1, LSR #7

//把buckets右移出去 剩下mask  实质是做 (_cmd ^(_cmd>>7))  & mask这样就拿到哈希 index

and p12, p12, p11, LSR #48 // x12 = (_cmd ^ (_cmd >> 7)) & mask

//index <<  4 意思  从开始的buckets 开始偏移 到index指向的bucket位置 

add p13, p10, p12, LSL #(1+PTRSHIFT)

// p13 = buckets + ((_cmd & mask) << (1+PTRSHIFT))

// do {

1: ldp p17, p9, [x13], #-BUCKET_SIZE //     {imp, sel} = *bucket--  意思是拿到对应的{imp,sel}到p9 比较

cmp p9, p1 //     if (sel != _cmd) {

b.ne 3f //         scan more

//     } else {

2: CacheHit \Mode // hit:    call or return imp  对比相同 就是缓存命中 意思是找到了 

//     }

3: cbz p9, \MissLabelDynamic //     if (sel == 0) goto Miss;   //sel为0 意味着bucket为空 就是没有了

cmp p13, p10 // } while (bucket >= buckets)  //继续循环

b.hs 1b

如果没有CacheHit 怎么办?那就到MissLabelDynamic ;

__objc_msgSend_uncached

MethodTableLookup流程

_lookUpImpOrForward

3.慢速查找methodlist

到了这里 我们终于可以离开晦涩难懂的汇编;回到C++代码了  objc-runtime-new.mm里面

在缓存里面找不到方法, lookUpImpOrForward 慢速查找methodlist。

也就说 在汇编的_objc_msgSend  快速查找缓存里面是有这个方法;没有的到c++的lookUpImpOrForward 里面进行慢速查找methodlist。

那我们看看 底层是如果在 lookUpImpOrForward 里查找imp的?

在for循环里面

for (unsigned attempts = unreasonableClassCount();;){

//这个还是先查一次共享缓存,因为我们在进来lookUpImpOrForward 有对类进行初始化,有有相关函数进入共享缓存,如果调用的刚好是这些方法 那么久可以拿到IMP了

        if (curClass->cache.isConstantOptimizedCache(/* strict */true)) {

#if CONFIG_USE_PREOPT_CACHES

            imp = cache_getImp(curClass, sel);

            if (imp) goto done_unlock;

            curClass = curClass->cache.preoptFallbackClass();

#endif

        } else {

            // curClass method list.

            Method meth = getMethodNoSuper_nolock(curClass, sel);  //这里进入 search_method_list_inline 再走 findMethodInSortedMethodList (类在加载的时候会按sel的地址排序) 再走 findMethodInSortedMethodList 里面进入了二分查找查询方法

            if (meth) {//找到就结束

                imp = meth->imp(false);

                goto done;

            }

            if (slowpath((curClass = curClass->getSuperclass()) == nil)) {//找父类 判断父类是否为空

                // No implementation found, and method resolver didn't help.

                // Use forwarding.

                imp = forward_imp;//找完了都没有 返回forward_imp

                break;

            }

        }

        // Halt if there is a cycle in the superclass chain.

        if (slowpath(--attempts == 0)) {

            _objc_fatal("Memory corruption in class list.");

        }

        // Superclass cache.

        // 父类 快速 -> 慢速 ->

        imp = cache_getImp(curClass, sel);

        if (slowpath(imp == forward_imp)) {

            // Found a forward:: entry in a superclass.

            // Stop searching, but don't cache yet; call method

            // resolver for this class first.

            break;

        }

        if (fastpath(imp)) {

            // Found the method in a superclass. Cache it in this class.

            goto done;

        }

    }

4.找不到方法报错

在慢查找还没不到 就会在objc_defaultForwardHandler 报错

objc_defaultForwardHandler(id self, SEL sel)

{

    _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);

}

看上面才知道 原来所谓的+方法 - 方法 只不过是OC自己加上去的符号而已。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值