首先附上常见类和类型的定义:
typedef struct objc_class *Class;
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
//SEL 可以将其理解为方法的 ID. 结构如下:
typedef struct objc_selector *SEL;
// IMP 可以理解为函数指针,指向了最终的实现
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
// 成员变量地址列表
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
// 方法地址列表
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
// 缓存最近使用的方法地址,以避免多次在方法地址列表中查询,提升效率
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
// 遵循的协议列表
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
NSObject.mm中的该方法实现如下:
// 传入的参数为SEL对象
- (BOOL)respondsToSelector:(SEL)sel {
// 参数分别为:当前对象,SEL对象,当前对象的class
return class_respondsToSelector_inst(self, sel, [self class]);
}
class_respondsToSelector_inst方法的实现如下:
NEVER_INLINE BOOL
class_respondsToSelector_inst(id inst, SEL sel, Class cls)
{
// 检测sel是否为nil、cls是否为nil、执行lookUpImpOrNil方法判断能够找到实现方法
return sel && cls && lookUpImpOrNil(inst, sel, cls, LOOKUP_RESOLVER);
}
关于枚举数据LOOKUP_RESOLVER的定义如下:
/* method lookup */
enum {
LOOKUP_INITIALIZE = 1,
LOOKUP_RESOLVER = 2,
LOOKUP_CACHE = 4,
LOOKUP_NIL = 8,
};
lookUpImpOrNil方法的实现如下:
// behavior具备默认值0
static inline IMP
lookUpImpOrNil(id obj, SEL sel, Class cls, int behavior = 0)
{
// 将传入的behavior和LOOKUP_CACHE、LOOKUP_NIL进行或操作
// 代表会同时检索这几种类型的SEL
return lookUpImpOrForward(obj, sel, cls, behavior | LOOKUP_CACHE | LOOKUP_NIL);
}
lookUpImpOrForward实现如下:
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
// 供外部使用的imps
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
IMP imp = nil;
Class curClass;
// 不加锁的查找cache
runtimeLock.assertUnlocked();
if (fastpath(behavior & LOOKUP_CACHE)) {
imp = cache_getImp(cls, sel);
if (imp) goto done_nolock;
}
// 上锁,开始搜索
runtimeLock.lock();
// 检测该类是否合法,此检查在流程启动期间非常昂贵
checkIsKnownClass(cls);
// swift环境下类初始化检测
if (slowpath(!cls->isRealized())) {
cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
// runtimeLock可能已被删除,但现在再次被锁定
}
// 确保该类已被初始化,如果没有就调用类方法+initialize,这里也说明了为什么OC的类会在
// 第一次接收消息后调用+initialize进行初始化,相反的,如果想要代码在类注册runtime的
// 时候就运行,可以将代码写在+load方法里
if (slowpath((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized())) {
cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
// runtimeLock可能已被删除,但现在再次被锁定
}
// 对消息查找和填充cache加锁,由于填充cache是写操作,所以需要对其加锁
// 以免加入了category之后的cache被旧的cache冲掉,导致category失效。
runtimeLock.assertLocked();
curClass = cls;
// 在该类及其父类中查找该SEL
for (unsigned attempts = unreasonableClassCount();;) {
// 当前类的方法列表
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
imp = meth->imp;
goto done;
}
// 乐观缓存查找——从缓存方法列表中快速查找
if (slowpath((curClass = curClass->superclass) == nil)) {
imp = forward_imp;
break;
}
// 如果超类链中存在循环,则暂停
if (slowpath(--attempts == 0)) {
_objc_fatal("Memory corruption in class list.");
}
// 父类缓存的方法
imp = cache_getImp(curClass, sel);
if (slowpath(imp == forward_imp)) {
break;
}
if (fastpath(imp)) {
// 在超类中找到该方法。将其缓存在此类中
goto done;
}
}
// 找不到实现,尝试一次方法解析
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior);
}
done:
log_and_fill_cache(cls, imp, sel, inst, curClass);
// 解锁
runtimeLock.unlock();
done_nolock:
if (slowpath((behavior & LOOKUP_NIL) && imp == forward_imp)) {
return nil;
}
// 返回查找到的imp
return imp;
}
关于以上代码中出现的函数及宏定义标示符注解如下:
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
static Class
realizeClassMaybeSwiftAndLeaveLocked(Class cls, mutex_t& lock)
{
return realizeClassMaybeSwiftMaybeRelock(cls, lock, true);
}
static Class
realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
{
lock.assertLocked();
if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
// Non-Swift class. Realize it now with the lock still held.
// fixme wrong in the future for objc subclasses of swift classes
realizeClassWithoutSwift(cls, nil);
if (!leaveLocked) lock.unlock();
} else {
// Swift class. We need to drop locks and call the Swift
// runtime to initialize it.
lock.unlock();
cls = realizeSwiftClass(cls);
ASSERT(cls->isRealized()); // callback must have provoked realization
if (leaveLocked) lock.lock();
}
return cls;
}
static unsigned unreasonableClassCount()
{
runtimeLock.assertLocked();
int base = NXCountMapTable(gdb_objc_realized_classes) +
getPreoptimizedClassUnreasonableCount();
// Provide lots of slack here. Some iterations touch metaclasses too.
// Some iterations backtrack (like realized class iteration).
// We don't need an efficient bound, merely one that prevents spins.
return (base + 1) * 16;
}
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
// fixme nil cls?
// fixme nil sel?
auto const methods = cls->data()->methods();
for (auto mlists = methods.beginLists(),
end = methods.endLists();
mlists != end;
++mlists)
{
// getMethodNoSuper_nolock is the hottest
// caller of search_method_list, inlining it turns
// getMethodNoSuper_nolock into a frame-less function and eliminates
// any store from this codepath.
method_t *m = search_method_list_inline(*mlists, sel);
if (m) return m;
}
return nil;
}
转载时请注明“来自-EvenZhu”