/// A pointer to the function of a method implementation. #if !OBJC_OLD_DISPATCH_PROTOTYPES typedef void (*IMP)(void /* id, SEL, ... */ ); #else typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); #endif
上面介绍的 SEL 就是为了查找方法的最终实现 IMP 的。由于每个方法对应唯一的 SEL,因此我们可以通过 SEL 方便快速准确地获得它所对应的 IMP。
实例(objc_object)
查看 objc/objc.h 中 objc_object 结构体的定义如下:
1 2 3 4 5 6
/// Represents an instance of a class. struct objc_object { Class _Nonnull isa OBJC_ISA_AVAILABILITY; }; /// A pointer to an instance of a class. typedef struct objc_object *id;
可以看到,实例的定义中只有一个 isa 指针字段,它是指向本类的指针。根据 objc_class 定义可以得知关于这个对象的所有基本信息都存储在 objc_class 中。所以,objc_object 需要的就是一个指向其类对象的 isa 指针。这样当我们向一个 Objective-C 对象发送消息时,Runtime 会根据实例对象的 isa 指针找到这个实例对象所属的类。
元类(Meta Class)
当我们调用对象方法时(即给实例对象发送消息),是根据 isa 指针寻找到这个对象(objc_object)的类(objc_class),再寻找到对应的方法实现。对应的我们调用类方法时(即给类对象发送消息),也需要根据 isa 指针寻找到一个包含这些类方法的一个 objc_class 结构体。这就引出了 meta-class 的概念,元类中保存了创建类对象以及类方法所需的所有信息。
// runtimeLock is held during isRealized and isInitialized checking // to prevent races against concurrent realization.
// runtimeLock is held during method search to make // method-lookup + cache-fill atomic with respect to method addition. // Otherwise, a category could be added but ignored indefinitely because // the cache was re-filled with the old value after the cache flush on // behalf of the category.
runtimeLock.lock(); checkIsKnownClass(cls);
if (!cls->isRealized()) { realizeClass(cls); }
if (initialize && !cls->isInitialized()) { runtimeLock.unlock(); _class_initialize (_class_getNonMetaClass(cls, inst)); runtimeLock.lock(); // 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 }
// 查找方法列表, 传入类对象和方法名 // Try this class's method lists. { // 根据sel去类对象里面查找方法 Method meth = getMethodNoSuper_nolock(cls, sel); if (meth) { // 如果方法存在,则缓存方法 log_and_fill_cache(cls, meth->imp, sel, inst, cls); // 方法缓存之后, 取出imp, 调用done返回imp imp = meth->imp; goto done; } } // 如果类方法列表中没有找到, 则去父类的缓存中或方法列表中查找方法 // Try superclass caches and method lists. { unsigned attempts = unreasonableClassCount(); for (Class curClass = cls->superclass; curClass != nil; curClass = curClass->superclass) { // Halt if there is a cycle in the superclass chain. if (--attempts == 0) { _objc_fatal("Memory corruption in class list."); } // 查找父类的缓存 // Superclass cache. imp = cache_getImp(curClass, sel); if (imp) { if (imp != (IMP)_objc_msgForward_impcache) { // 在父类中找到方法, 在本类中缓存方法, 注意这里传入的是cls, 将方法缓存在本类缓存列表中, 而非父类中 // 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 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.unlock(); _class_resolveMethod(cls, sel, inst); runtimeLock.lock(); // 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.
if (resolver && !triedResolver) { runtimeLock.unlock(); _class_resolveMethod(cls, sel, inst); runtimeLock.lock(); // 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; }
void _class_resolveMethod(Class cls, SEL sel, id inst) { if (! cls->isMetaClass()) { // try [cls resolveInstanceMethod:sel] _class_resolveInstanceMethod(cls, sel, inst); } else { // try [nonMetaClass resolveClassMethod:sel] // and [cls resolveInstanceMethod:sel] _class_resolveClassMethod(cls, sel, inst); if (!lookUpImpOrNil(cls, sel, inst, NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) { _class_resolveInstanceMethod(cls, sel, inst); } } }
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //执行foo函数 [self performSelector:@selector(foo:)]; }