返回
消息流分析的宝贵指南:快速查找过程的深度揭示
IOS
2024-01-21 14:43:54
Objective-C中的消息流分析:快速查找过程
在上一篇文章中,我们探索了实例对象调用实例方法时,方法insert将sel和imp插入到cache的过程。现在,我们再来看看,当调用方法时,是如何从cache中将其取出来的,即sel-imp的快速查找。
源码查看
- (void) 快速查找:(id)self 方法名称:(SEL)aSelector {
SEL sel;
IMP imp;
查找的代码;
if (sel == aSelector) {
imp = methodCache.imp;
}
dispatch_once(&onceToken, ^{
class_cacheEntry *cacheEntry =
(class_cacheEntry *)objc_msgSend(methodCache.class, @selector(classCacheEntry));
cacheEntry->entries = (__strong void *)malloc(cacheEntry->mask + 1);
cacheEntry->probes = (__strong void *)malloc(cacheEntry->mask + 1);
});
cacheEntry *ce = methodCache.classCacheEntry;
uintptr_t mask = methodCache.mask;
uintptr_t idx = sel & mask;
NSUInteger count = ce->entries[idx];
NSUInteger probe = 0;
NSUInteger i;
for (i = idx; i <= mask; i++) {
if (ce->entries[i] == count) {
break;
}
sel_imp_entry *entry = &ce->entries[i];
if (entry->sel == sel && sel != 0) {
imp = entry->imp;
break;
} else {
uintptr_t x = ce->probes[i];
if (x & 0x1) {
probe = i;
ce->probes[i] = x | 1;
break;
} else {
ce->probes[i] = x | 1;
}
}
}
for (i = idx - 1; i >= 0; i--) {
if (ce->entries[i] == count) {
break;
}
sel_imp_entry *entry = &ce->entries[i];
if (entry->sel == sel && sel != 0) {
imp = entry->imp;
break;
} else {
uintptr_t x = ce->probes[i];
if (x & 0x1) {
probe = i;
ce->probes[i] = x | 1;
break;
} else {
ce->probes[i] = x | 1;
}
}
}
if (probe != 0) {
cacheEntry->entries[probe] = count;
cacheEntry->entries[idx] = probe;
cacheEntry->entries[i] = count;
}
return imp;
}
快速查找过程步骤
-
首先,通过sel和aSelector进行比较,如果两者相等,则直接从methodCache中获取imp。
-
随后,通过dispatch_once函数确保classCacheEntry被正确初始化。
-
接下来,根据sel的值计算出idx和mask,并获取classCacheEntry的entries和probes。
-
接着,通过循环遍历entries,查找与sel相等的项,如果找到,则直接返回imp。
-
如果在entries中找不到匹配项,则通过循环遍历probes,找到第一个值为1的项,并将其置为2,然后将该项对应的entries项设置为count。
-
最后,如果在probes中也没有找到匹配项,则返回nil。
总结
在Objective-C中,快速查找过程对于高效的消息传递至关重要。通过了解快速查找的实现细节,我们可以更深入地理解Objective-C的底层原理,并优化应用程序的性能。