我们都知道Objetive-C 是一门动态语言,其最基本的的东西就是它的消息机制。运行时的最底层函数就是 objc_msgSend方法, 它就是负责发送一个消息给对象的C函数。所以Objective-C中调用方法其实就是向对象发送消息,比如:
PerSon *per = [[PerSon alloc]init];
[per testPerson];
- 这句代码的含义就是向对象obj发送testPerson的消息,编译器会调用底层的obj_msgSend( ),其实最终调用方式为:
objc_msgSend(per,@selector(testPerson));
通过导入 #import <objc/message.h> 头文件查看objc_msgSend函数
xcode6之前, 苹果可以使用objc_msgSend, 而且有参数提示
* xcode6之后不推荐使用Runtime
* 解决方法: 找到build setting -> 搜索msg, 改成NO, 不用严格检查
这样Runtime就正常了
-
Runtime为了提高消息发送效率,objc_msgSend底层是用汇编写成。存在于objc-msg-x86_64.s中。 我们可以通过调试打印出对应的汇编方法。
-
调试汇编步骤: Debug ->DebugWorkFlow->Always show Disassambly
由上图可见在代码 25行和32行可见 bl 指令(在汇编中bl指令就是跳转指令,相当于goto )
所以认为程序是跳转到 objc_msgSend 方法中执行了,点击下一步继续往下走。
-
接下来开始调用 _objc_msgSend_uncached 方法,这时可以推测 在消息发送过程中先查找了一下缓存。 继续查看 objc_msgSend_uncached 方法里 找到 _class_lookupMethodAndLoadCache3方法
-
接下来 打开 runTime源码 查看 _class_lookupMethodAndLoadCache3 方法内部构造
再次点击去看看
lookUpImpOrForward.png
// 4. 执行查找imp和转发的代码
IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
IMP imp = nil;
bool triedResolver = NO;
runtimeLock.assertUnlocked();
// 如果cache是YES,则从缓存中查找IMP。如果是从cache3函数进来,则不会执行cache_getImp()函数
if (cache) {
// 通过cache_getImp函数查找IMP,查找到则返回IMP并结束调用
imp = cache_getImp(cls, sel);
if (imp) return imp;
}
runtimeLock.read();
// 判断类是否已经被创建,如果没有被创建,则将类实例化
if (!cls->isRealized()) {
runtimeLock.unlockRead();
runtimeLock.write();
// 对类进行实例化操作
realizeClass(cls);
runtimeLock.unlockWrite();
runtimeLock.read();
}
// 第一次调用当前类的话,执行initialize的代码
if (initialize && !cls->isInitialized()) {
runtimeLock.unlockRead();
// 对类进行初始化,并开辟内存空间
_class_initialize (_class_getNonMetaClass(cls, inst));
runtimeLock.read();
// If sel == initialize, _class_initialize will send +initialize and
// then the messenger will send +initialize again after this
// procedure finishes. Of course, if this is not being called
// from the messenger then it won't happen. 2778172
}
retry:
runtimeLock.assertReading();
// 尝试获取这个类的缓存
imp = cache_getImp(cls, sel);
if (imp) goto done;
{
// 如果没有从cache中查找到,则从方法列表中获取Method
Method meth = getMethodNoSuper_nolock(cls, sel);
if (meth) {
// 如果获取到对应的Method,则加入缓存并从Method获取IMP
log_and_fill_cache(cls, meth->imp, sel, inst, cls);
imp = meth->imp;
goto done;
}
}
// Try superclass caches and method lists.
{
unsigned attempts = unreasonableClassCount();
// 循环获取这个类的缓存IMP 或 方法列表的IMP
for (Class curClass = cls->superclass;
curClass != nil;
curClass = curClass->superclass) //当前的Superclalss
{
// Halt if there is a cycle in the superclass chain.
if (--attempts == 0) {
_objc_fatal("Memory corruption in class list.");
}
// Superclass cache.
// 获取父类缓存的IMP
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_t对象。如果找到则缓存查找到的IMP
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
imp = meth->imp;
goto done;
}
}
}
// 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;
}
// No implementation found, and method resolver didn't help.
// Use forwarding.
// 如果没有IMP被发现,并且动态方法解析也没有处理,则进入消息转发阶段
imp = (IMP)_objc_msgForward_impcache;
cache_fill(cls, sel, imp, inst);
done:
runtimeLock.unlockRead();
return imp;
}
其中看看 getMethodNoSuper_nolock 这个函数
// 根据传入的SEL,查找方法列表中的method_t对象
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
runtimeLock.assertLocked();
assert(cls->isRealized());
// 根据for循环,从methodList列表中,从头开始遍历,每次遍历后向后移动一位地址。
for (auto mlists = cls->data()->methods.beginLists(),
end = cls->data()->methods.endLists();
mlists != end;
++mlists)
{
// 对sel参数和method_t做匹配,如果匹配上则返回。
method_t *m = search_method_list(*mlists, sel);
if (m) return m;
}
return nil;
}
关于 search_method_list 函数
// 根据传入的SEL,查找对应的method_t结构体
static method_t *search_method_list(const method_list_t *mlist, SEL sel)
{
int methodListIsFixedUp = mlist->isFixedUp();
int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);
//数组中查找方法实现 (检测是否为有序还是无序)
if (__builtin_expect(methodListIsFixedUp && methodListHasExpectedSize, 1)) {
//已经排好序 用二分查找
return findMethodInSortedMethodList(sel, mlist);
} else {
//没有排序 就遍历查找
for (auto& meth : *mlist) {
// SEL本质上就是字符串,查找的过程就是进行字符串对比
if (meth.name == sel) return &meth;
//所以比对的就是 name name也就是方法编号
}
}
#if DEBUG
// sanity-check negative results
if (mlist->isFixedUp()) {
for (auto& meth : *mlist) {
if (meth.name == sel) {
_objc_fatal("linear search worked when binary search did not");
}
}
}
#endif
return nil;
}
查找方法 总结:
1.去类对象中的方法列表 查找对应的对象的 Method_t() 这个结构体 比对 结构体的 method_t.name 和查找的sel
找到了返回地址空间 &method_t
网友评论