Cache读取流程分析
通过对cache_t的学习,我们了解到类或对象的方法是通过insert操作来加入缓存的,具体什么时候进行insert操作,我们在insert的地方加入断点,查看函数调用栈:
log_and_fill_cache调用了insert:
lookUpImpOrForward调用了log_and_fill_cache
到此为止,便是C++对cache的调用流程。
Runtime的运行时理解
1、Runtime在OC框架中的位置:
2、调用Runtime的三种方式:
3、编译OC代码,通过clang 生成 .cpp文件.
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main.cpp
LGPerson *person = [LGPerson alloc];
[person sayNB];
[person sayHello];
//编译后的结果对照
LGPerson *person = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"),sel_registerName("alloc"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)person,sel_registerName("sayNB"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)person,sel_registerName("sayHello"));
//调用方法 = 消息发送: objc_msgSend(消息的接受者,消息的主体(sel+参数))
苹果文档地址: developer.apple.com/documentati…
objc_msgSend流程
查找objc_msgSend 汇编源码
分享个使用的快捷键: command + 鼠标点击一个左侧的箭头 折叠所有项
找到 ENTRY入口,以下是_objc_msgSend的汇编实现以及具体分析:
_objc_msgSend
······
ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame
//p0是消息接受者的地址,这里判断消息接收者是否存在
cmp p0, #0 // nil check and tagged pointer check
// 判断是否支持Taggedpointer类型
#if SUPPORT_TAGGED_POINTERS
// 如果支持Taggedpointer类型,按照LNilOrTagged处理
b.le LNilOrTagged // (MSB tagged pointer looks negative)
#else
// 如果不支持Taggedpointer类型,直接返回LReturnZero
b.eq LReturnZero
#endif
// p13 = isa [x0]存放的是class
ldr p13, [x0] // p13 = isa
GetClassFromIsa_p16 p13, 1, x0 // p16 = class
//receiver -> class -> objc_msgSend -> cache
LGetIsaDone:
// calls imp or objc_msgSend_uncached
CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached
#if SUPPORT_TAGGED_POINTERS
LNilOrTagged:
b.eq LReturnZero // nil check
GetTaggedClass
b LGetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif
······
上面分析到 GetClassFromIsa_p16 p13, 1, x0 这一步,需要查看这个方法具体是什么,做了哪些事情?
GetClassFromIsa_p16
// GetClassFromIsa_p16 p13, 1, x0; src=p13=isa needs_auth=1 auth_address=x0
.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
.else
// 64-bit packed isa
// 操作结束之后,p16是接收者的class
ExtractISA p16, \src, \auth_address
.endif
#else
// 32-bit raw isa
mov p16, \src
#endif
.endmacro
ExtractISA
.macro ExtractISA
// $0=p16,$1=src=isa,解释:$1与ISA_MASK进行`与`操作得到的class,存到$0=p16
and $0, $1, #ISA_MASK
.endmacro
知识点:
1、p $3[1] 当$3是指针的时候,代表指针平移一个单位,相当于 $3+1
面试题
下面代码的打印结果:
- (instancetype)init{
self = [super init];
if (self) {
NSLog(@"%@",NSStringFromClass([self class]));
NSLog(@"%@",NSStringFromClass([super class]));
}
return self;
}
如果类是Person,那么打印结果如下:
Person
Person
解析
1、oc和cpp代码对比
使用clang生成cpp文件,
clang -rewrite-objc LGPerson.m
上面OC代码对应的C++代码:
static instancetype _I_LGPerson_init(LGPerson * self, SEL _cmd) {
if (self = ((LGPerson *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LGPerson"))}, sel_registerName("init"))) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_vj_4mx0r3r94cb6lxl6pxdh225r0000gn_T_LGPerson_088d3d_mi_0,NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_vj_4mx0r3r94cb6lxl6pxdh225r0000gn_T_LGPerson_088d3d_mi_1,NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LGPerson"))}, sel_registerName("class"))));
}
return self;
}
精简一下,方便阅读
objc_msgSend(self, sel_registerName("class"));
objc_msgSendSuper({self,class_getSuperclass(objc_getClass("LGPerson"))}, sel_registerName("class"));
2、objc_msgSend 和 objc_msgSendSuper方法的定义
OBJC_EXPORT id _Nullable
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
OBJC_EXPORT id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
objc_super 结构体
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained _Nonnull Class class;
#else
__unsafe_unretained _Nonnull Class super_class;//是第一次查找的类
#endif
/* super_class is the first class to search */
};
#endif
3、总结
super 调用 objc_msgSendSuper 告诉系统直接去父类方法列表里面去找,但是调用者主体还是 self,和 self 的区别只是省去了在本类的方法列表中查找的步骤。
[self class] 、[super class],class 这个方法都是 在 NSObject 对象中找到的,所以都相当于 调用 [self class], 输出都是 一样的。