返回

消息流分析的宝贵指南:快速查找过程的深度揭示

IOS

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;
}

快速查找过程步骤

  1. 首先,通过sel和aSelector进行比较,如果两者相等,则直接从methodCache中获取imp。

  2. 随后,通过dispatch_once函数确保classCacheEntry被正确初始化。

  3. 接下来,根据sel的值计算出idx和mask,并获取classCacheEntry的entries和probes。

  4. 接着,通过循环遍历entries,查找与sel相等的项,如果找到,则直接返回imp。

  5. 如果在entries中找不到匹配项,则通过循环遍历probes,找到第一个值为1的项,并将其置为2,然后将该项对应的entries项设置为count。

  6. 最后,如果在probes中也没有找到匹配项,则返回nil。

总结

在Objective-C中,快速查找过程对于高效的消息传递至关重要。通过了解快速查找的实现细节,我们可以更深入地理解Objective-C的底层原理,并优化应用程序的性能。