目录:
01-Runtime 初探
02-Runtime 对象与方法的本质
03-Runtime 动态方法解析
04-Runtime 消息转发
05-Runtime应用
01-Runtime 初探
runtime:c /C++汇编一起写成的api ——》OC运行时
运行时:装在到内存 提供运行时功能
// 代码 ---> 编译链接 ---> 执行
// 对于C函数就是静态性,我编译如果不存在这个run函数,就会报错,但是OC不一样
02-Runtime 对象与方法的本质
//clang 成C++后:
eg:
LGPerson *p = [[LGPerson alloc] init];
// LGPerson *p = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("new"));
总结:任何OC方法的调用都会编译成C++的一句代码:objc_msgSend
。
OC 对象 -- 本质 --- 结构体
方法的本质 --- 发送消息
// objc_msgSend ?
// 消息的组成
[p run];
// ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
**
`void *)objc_msgSend)((id)p `消息接受者
`sel_registerName("run") ` 方法编号 --- name
` imp` 函数实现的指针 -- sel -> imp ?
// 下层通讯 方法 -- 对象 类
// 父类发送消息
// github 写了注释的代码
**
---
sel -> imp ?
如何通过sel找到imp指针呢
##2.1类方法与实例方法
(**类的类方法** 和 **元类的对象实例方法** 是一样的东西)
runtime三种调用方式
1.runtime api
2.NSObject `isMenberof iskindof`
3.OC上层方法 `@selector`
---
objc_msgSend: 实现的两种方式
1.快速: 缓存 汇编
2.慢速: C 和 C++ 和 汇编 一起完成
![缓存在对象结构体中的位置](https://img.haomeiwen.com/i2144862/2fb22ab8fa663526.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
objc_msgSend1快速流程:
cache_t 找方法,objc_msgSend通过sel找对应的imp,如果在cache_t里面,通过一个hash表找到;
objc_msgSend2慢速流程:
找不到就会用C look up 往上找,复杂的过程,找到后存到cache_t
###为什么要用汇编写objc_msgSend?
1.C无法实现: 写一个函数,保存位置的参数,跳转任意指针;
2.汇编可以:使用 寄存器 x0 x31,运行速度快;
---
(tagged pointer 特殊的数据类型)
##2.2源码分析流程,方法查找:(汇编部分,runtime源码)上往下执行;
`_objc_msgSend`
`LNilOrTagged`
`LGetIsaDone` isa处理完毕
LGetIsaDone:
CacheLookup NORMAL // calls imp or objc_msgSend_uncached
`CacheLookup NORMAL` // calls imp or objc_msgSend_uncached
人话:处理完isa后 cache查找imp,如果能找就call imp(快速),找不到返回`objc_msgSend_uncached`
进入
`.macro CacheLookup`
.macro CacheLookup
// x1 = SEL, x16 = isa
ldp x10, x11, [x16, #CACHE] // x10 = buckets, x11 = occupied|mask
and w12, w1, w11 // x12 = _cmd & mask
add x12, x10, x12, LSL #4 // x12 = buckets + ((_cmd & mask)<<4)
ldp x9, x17, [x12] // {x9, x17} = *bucket
1: cmp x9, x1 // if (bucket->sel != _cmd)
b.ne 2f // scan more
CacheHit $0 // call or return imp
2: // not hit: x12 = not-hit bucket
CheckMiss $0 // miss if bucket->sel == 0
cmp x12, x10 // wrap if bucket == buckets
b.eq 3f
ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket
b 1b // loop
3: // wrap: x12 = first bucket, w11 = mask
add x12, x12, w11, UXTW #4 // x12 = buckets+(mask<<4)
// Clone scanning loop to miss instead of hang when cache is corrupt.
// The slow path may detect any corruption and halt later.
ldp x9, x17, [x12] // {x9, x17} = *bucket
1: cmp x9, x1 // if (bucket->sel != _cmd)
b.ne 2f // scan more
CacheHit $0 // call or return imp
2: // not hit: x12 = not-hit bucket
CheckMiss $0 // miss if bucket->sel == 0
cmp x12, x10 // wrap if bucket == buckets
b.eq 3f
ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket
b 1b // loop
3: // double wrap
JumpMiss $0
.endmacro
三种情况
`CacheHit`直接返回
`CheckMiss`找不到,进入`objc_msgSend_uncached`
`add`没有,add当前的imp到缓存cache
---
###2.2.1慢速查找流程分析:上往下执行;
####`objc_msgSend_uncached`开始:
**进入`_class_lookupMethodAndLoadCache3`,此处走出汇编进入`objc-runtime-new.mm`(c/c++混编部分)**
IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
{
return lookUpImpOrForward(cls, sel, obj,
YES/initialize/, NO/cache/, YES/resolver/);
}
`lookUpImpOrForward`
`realizeClass(cls)`
`_class_initialize`
`imp = cache_getImp(cls, sel)` 为了 `remap(`重映射 ?
`漫长过程` 找方法 ——>找方法——>找自己——>找老爹——>NSObject
//当前找:
// Try this class's method lists.
{
Method meth = getMethodNoSuper_nolock(cls, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, cls);
imp = meth->imp;
goto done;
}
}
//老爹找:
// Try superclass caches and method lists.
{
unsigned attempts = unreasonableClassCount();
for (Class curClass = cls->superclass;
curClass != nil;
curClass = curClass->superclass)
{
// Halt if there is a cycle in the superclass chain.
if (--attempts == 0) {
_objc_fatal("Memory corruption in class list.");
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
if (imp) {
if (imp != (IMP)_objc_msgForward_impcache) {
// Found the method in a superclass. Cache it in this class.
log_and_fill_cache(cls, imp, sel, inst, curClass);
goto done;
}
else {
// Found a forward:: entry in a superclass.
// Stop searching, but don't cache yet; call method
// resolver for this class first.
break;
}
}
// Superclass method list.
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
imp = meth->imp;
goto done;
}
}
}
---
#03-Runtime 动态方法解析
`_class_resolveMethod`
//找自己找父类找不到,就执行一次动态方法解析
// No implementation found. Try method resolver once.
if (resolver && !triedResolver) {
runtimeLock.unlockRead();
_class_resolveMethod(cls, sel, inst);
runtimeLock.read();
// Don't cache the result; we don't hold the lock so it may have
// changed already. Re-do the search from scratch instead.
triedResolver = YES;
goto retry;
}
pragma mark - 动态方法解析 重写
-
(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"来了 老弟");
return [super resolveInstanceMethod:sel];
} -
(BOOL)resolveClassMethod:(SEL)sel{
NSLog(@"来了 老弟");
return [super resolveClassMethod:sel];
}
`lookup imp没有`
`_class_resolveMethod` 动态方法决议,只调用一次;
调用前判断:if不是元类
是,调用`resolveInstanceMethod`
否则调用`resolveClassMethod`
#04-Runtime 消息转发
//类消息转发
//只有汇编调用 没有源码实现
![动态方法决议
](https://img.haomeiwen.com/i2144862/937a2617f32cf856.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
//系统调用堆栈
//沙盒
//切面变成
//家庭作业 aspect ——— 消息转发代码
//method-swizzling hook array 数组越界
//self.dataArray objectAtIndex
//if index < self.count-1 -- exception
//消息转发
---
#5Runtime应用
网友评论