OC-消息机制

什么是消息机制

相较于C++的函数调用方式 OC采用的是消息传递
下面我们来对两种方式做一个类比
在函数调用中如果要使用一个函数,一般是将参数压入栈 再寻找函数地址 将参数从栈中拿出 得出结果再返回原来运行处 再进行调用。或者是在编译时就将代码在调用处展开
而消息传递是不管你是否多态,总是在运行时才会去查找所要执行的方法。
所以使用消息结构的语言,其运行时所应执行的代码由运行环境来决定;而使用函数调用的语言则由编译器决定

什么是消息选择器

向一个对象发送消息时简单的代表了一个方法名 比如[a func]此时func是选择器
当源代码编译时选择器会被指向一个唯一标识(SEL)以代替方法名 此时SEL是选择器
主要是为了更快编译
SEL就是消息选择器 SEL s1 = @selector(func); // @selector()就是引用编译后的选择器

为什么要消息选择器

出于运行效率的考虑,在编译后的代码中不会使用有ASCII码组成的方法名,
取而代之的是,编译器会将每个方法名写到一张表去,然后为每个方法名分
配一个唯一标识用于在运行时标识一个方法
SEL sor; (sor就是消息选择器 也可以看作唯一标识)
-(void)who:(int)n;
sor = @selector(who:);
注意!这个sor标识的只是方法名!并不是指定了就是这个方法实现

消息机制的本质

objc_msgSend

void objc_msgSend(id self, SEL cmd,…);//是一个可变参数函数
第一个参数是接受消息的对象 第二个是消息本身,方法的名字 后面的就是消息中的那些参数
当编译器看到消息后 就会将其转化成一条标准的C语言函数调用。
例如
[a func:x];被转化为
objc_msgSend(a,@selector(func),x);

消息机制的整个过程

A *a = [[A alloc]init];
[a func]
objc_msgSend(a,@select(func))

进入objc_msgSend后会通过CacheLookup找一下cache(我猜目的就是看最近有没有调用过func这个方法 如果调用过那就会把cache放进来)
如果没找到 就会调用

_objc_msgSend_uncached//在objc_msgSend函数里

这个函数会调用

_class_lookupMethodAndLoadCache3(id, SEL, Class);//id大概率是self也就是a  SEL是@select(func) Class是A

//函数定义
IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)//应该就是帮lookUpImpOrForward补一下参数
{
    return lookUpImpOrForward(cls, sel, obj, 
                              YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
}

然后_class_lookupMethodAndLoadCache3会调用

lookUpImpOrForward

从下面开始都是在lookUpImpOrForward中
lookUpImpOrForward会先调用

cache_getImp//就是调用CacheLookuo找一下cache 找不到返回nil

再判断!cls->isRealized() 如果条件成真则调用

realizeClass(cls);

上面这些都不是很重要 重点在这

meth = _class_getMethodNoSuper_nolock(cls, sel);//Method meth;

_class_getMethodNoSuper_nolock通过调用search_method_list(自己看的只找到_findMethodInClass)去当前类的method list(分发表)中通过sel看是否有这个method
如果是无序表则直接匹配 如果有序则调用findMethodInSortedMethodList
如果找到了这个method 则调用

log_and_fill_cache(cls, cls, meth, sel);///把方法加入到cache中
//(在cache已经3/4满的时候,就会调用expand()方法扩充,正常情况下,expand方法会将容量翻倍,通过调用reallocate方法给cache重新分配内存,但出于性能考虑不会将老cache中的内容拷贝到新cache中)

如果没有找到 则去父类中找

curClass = cls;
while ((curClass = curClass->superclass)) {
// Superclass cache. 先去父类的cache中找
	meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache);
	//。。。
	
	// Superclass method list. 再去父类的method list中找
	meth = _class_getMethodNoSuper_nolock(curClass, sel);

找到了就加到cache中
如果还没找到就调用

_class_resolveMethod(cls, sel, inst);

进入动态方法解析
如果还不行 则

_cache_addForwardEntry(cls, sel);
methodPC = _objc_msgForward_impcache;

到这里lookUpImpOrForward结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值