runtime初探
runtime
C C++ 汇编写成的API
OC 运行时
- legacy Version
早期版本Objctive-C 1.0 中32位的Mac OSX的平台
-
Mordern Version
-
2.0 objc源码750
-
Mac OS X V10.5以后的64系统
-
源码解析
id objc_msgSend(id self, SEL, _cmd,...)
汇编跟进来
ENTRY _objc_msgSend
-
1,如果指针小于LNilOrTagged 直接return返回
-
2,通过isa找到响应类class
-
3,CacheLookup 找我们一般参数:NORMAL
-
CacheLookup 是个宏定义
-
1,CacheHit $0
-
1,NORMAL MESSENGER_END_FAST 结束查找路径
-
2,GETIMP 直接返回对应参数就OK
-
3,LOOKUP
-
-
2,CheckMiss $0 就是找不到系列
-
1,GETIMP ---- LGetImpMiss
-
2,NORMAL ---- __objc_msgSend_uncached
-
就是说没有响应的缓存
-
接下来去 MethodTableLookup 方法列表查找
-
__class_lookupMethodAndLoadCache3 汇编查找
-
_class_lookupMethodAndLoadCache3 C函数
lookUpImpOrForward(cls, sel, obj, YES/*Initiailze*/, NO/*cache*/ 因为我们查找了没有 就没有必要传参cache,YES/*resclver*/)
-
imp = cache_getImp(cls,sel);----CacheLookup
-
接下来都是一些判断配置
-
核心:retry
-
cache_getImp 又去拿一次 因为OC动态语言,随时随地的都能操作修改,防止数据问题,再取一次。
-
1,getMethodNoSuper_nolock 从自己类的方法方法列表去找 --- 如果找到了就去填充到缓存。
-
2,cls -> superclass,cache_getImp(curClass, sel)从递归父类去找,直到NSObject
-
-
如果还没有找到:No Implementation found. Try method resolver once.
-
-
3,LOOKUP __objc_msgLookup_uncached
-
3: add
-
1,CacheHit
-
2,CheckMiss
-
3,JumpMiss
-
-
-
-
-
注意跟对架构 objc-msg-arm64.s
runtime 三种调用方式
- runtime api
(class_ ,objc_ .....)
- NSObject
(isKindOf:,isClassOf:......)
- 编译器提供的 OC上层方法:@selector
objc_msgSend 发送消息
-
两种方式:
-
快速 -> 汇编 -> 缓存中找到 imp 哈希表
缓存 cache_t 中找, -
慢速 -> C, C++, 汇编 -> 缓存
-
复杂的过程
-
-
c 写一个函数,保留未知的参数,跳转到任意函数中去。
-
块
-
汇编可以 寄存器 x0 x31
tagged pointer 特殊的数据类型
源码分析流程
1, 方法查找
汇编部分:
-
_objc_msgSend
-
LNilOrTagged
-
LGetLsaDone isa 处理完毕
-
Cache_Lookup NOEMAL 缓存中找imp
-
call imp
-
objc_msgSend_uncached
-
CacheHit -> CALL
-
CheckMiss -> _objc_msgSend_uncached -> MethodTableLookup
-
add
-
-
MethodTableLookup
-
bl __class_lookupMethodAndLoadCache3 -> C / C++
C / C++
-
lookUpImpOrForward
-
realizeClass(cls)
-
_class_initialize
-
漫长过程 -> 找方法
-
本类
-
父类 -> getMethodNoSuper_nolock
-
NSObject
-
getMethodNoSuper_nolock -> log_and_fill_cache
-
log_and_fill_cache
-
2, 动态方法解析
-
lookup imp没有
-
__class_resolveMethod
-
__class_resolveInstanceMethod
-
__class_resolveClassMethod
-
-
只有一次
-
3, 消息转发
-
forwardingTargetForSelector
-
自定义处理
-
防止崩溃
-
-
methodSignatureForSelector
-
forwardInvocation
-
指定一个简单的异行的方法
-
打印系统调用堆栈
-
打印的东西存到沙盒 -> 服务器
-
AOP 切面编程,埋点统计
作业:aspect -- 消息转发的源码
- method-swizzing hook array 数组越界:
[self.dataArray objcAtIndex ]
if index < self.dataArray.count - 1 --excepetion -
-
instrumentObjcMessageSends
打印所有关于objc调用堆栈的一些信息
runtime 应用调用
runloop
KVC
KVO
运行时
代码 -- 编译连接 -- 执行
对于C函数就是静态性,编译如果不存在这个run函数,就会报错,但是OC 不一样。
OC代码run起来之后,会被装在进内存。不存在函数运行时不会报错,只有到调用的时候,如果不存在这个函数方法,OC才会报错。
- OC 对象 -- 本质 -- 结构体
类方法 元类 -- 姿态 实例方法
对象 在 类 实例
类 在元类 实例
编译时
编译时,就是编译器把源代码翻译成机器能够识别的语言。
代码跑起来,被装填到内存中去。
OC swift java
高级语言,可读性较强,不会被机器所识别,需要转成机器语言汇编,最终会转换成二进制
OC对象
OC 对象 - 本质 -- 结构体
编译 clang
Person *p = [[Person alloc] init];
Person *p = ((Person ()(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
- 方法调用 objc_msgSend
- 方法的本质 --- 发送消息
- 消息的组成
(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("run"));
- (void *)objc_msgSend)((id)p) 消息的接受者
- sel_registerName("run") 方法编号 -- name
- imp 函数实现的指针 -- sel -> imp
下层通讯
方法 -- 对象 类
typedef struct objc_object LGPerson; 对象的本质就是结构体
每个对象的底层都有一个implist
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
父类发送消息
网友评论