运⾏时 就是代码跑起来了.被装载到内存中去了 . (你的代码保存在磁盘上没装⼊内存之前是个死家伙.只有跑到内存中才变成活的).⽽运⾏时类型检查就与前⾯讲的编译时类型检查(或者静态类型检查)不⼀样.不是简单的扫描代码.⽽是在内存中做些操作,做些判断.
即:编译器编译时会做一些操作和判断。
-
runtime 的三种使用方式
-
- Objective-C code @selector()
-
- NSObject 的方法 NSSelectorFromString()
-
- sel_registerName 函数 api
-
-
clang -rewrite-objc main.m -o main.cpp
-
oc中的代码
- c++中的转化
-
// 调用方法 = 消息发送 : objc_msgSend(消息的接受者,消息的主体(sel + 参数))
-
[LGPerson alloc];
等价于
objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("alloc"));
[person sayNB];
等价于objc_msgSend(person, @selector(sayNB));
等价于 objc_msgSend(person, sel_registerName("sayNB"));
- 这里修改为NO才能通过编译
- objc_super 结构体
- receiver : 消息发送的接收者 如person 对象
- super_class : 表示这个方法从哪个类中开始查找
- 注意此时 person 继承自 teacher 最后调用到了父类的 sayHello 方法
_objc_msgSend 汇编源码分析
- 汇编
cmp p0, #0 // nil check and tagged pointer check
p0寄存器中存放了函数的第一个参数即如:person对象,p0与#0 比较,消息接收者是否为空。b.le LNilOrTagged // (MSB tagged pointer looks negative)
判断是否为 tagged pointer 小对象类型 b 小于或等于 nil 或则 小对象 Yes: 进入 LNilOrTagged操作,NO:向下走b.eq LReturnZero
判断是否为空 YES:则跳转至 LReturnZero 进行操作 NO:向下走ldr p13, [x0] // p13 = isa
load 将[x0]数据写入到寄存器中 即:p13寄存器保存了 对象的isaGetClassFromIsa_p16 p13, 1, x0 // p16 = class
isa & 掩码 找到 class 将类地址存入到p16寄存器中。.macro GetClassFromIsa_p16 src, needs_auth, auth_address /* note: auth_address is not required if !needs_auth */ #if SUPPORT_INDEXED_ISA // Indexed isa mov p16, \src // optimistically set dst = src tbz p16, #ISA_INDEX_IS_NPI_BIT, 1f // done if not non-pointer isa // isa in p16 is indexed adrp x10, _objc_indexed_classes@PAGE add x10, x10, _objc_indexed_classes@PAGEOFF ubfx p16, p16, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS // extract index ldr p16, [x10, p16, UXTP #PTRSHIFT] // load class from array 1: #elif __LP64__ .if \needs_auth == 0 // _cache_getImp takes an authed class already mov p16, \src - 将p13寄存中的数据移动到p16寄存器中 .else // 64-bit packed isa ExtractISA p16, \src, \auth_address --- //将p13 & 掩码 后存入到 p16寄存器中,即:p16 存放了 class .endif #else // 32-bit raw isa mov p16, \src #endif .endmacro .macro ExtractISA and $0, $1, #ISA_MASK //将 $1 & 掩码 后存入到 $0 中 .endmacro 复制代码
- 上面的操作 通过 receiver 获取了 class :因为cache是存入在 class 中的,因为先找缓存中的方法
CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached
//开始查找缓存
上述流程
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END