之前讲到过实例对象的 isa 指向类对象,类对象的 isa 指向元类对象,当 people 实例对象调用 run 方法时,类对象的 isa 找到类对象的 isa,然后在类对象中查找对象方法,如果没有找到,就通过类对象的 superclass 找到父类对象,接着去寻找 run 方法。 分类中的对象方法依然是存储在类对象中的,同对象方法在同一个地方,那么调用步骤也同调用对象方法一样。如果是类方法的话,也同样是存储在元类对象中。
Category的结构
在 objc-runtime-new.h 中我们可以找到分类的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
structcategory_t { constchar *name; classref_t cls; structmethod_list_t *instanceMethods; structmethod_list_t *classMethods; structprotocol_list_t *protocols; structproperty_list_t *instanceProperties; // Fields below this point are not always present on disk. structproperty_list_t *_classProperties;
method_list_t *methodsForMeta(bool isMeta){ if (isMeta) return classMethods; elsereturn instanceMethods; }
/*********************************************************************** * _objc_init * Bootstrap initialization. Registers our image notifier with dyld. * Called by libSystem BEFORE library initialization time **********************************************************************/
for (i = 0; i < count; i++) { category_t *cat = catlist[i]; Class cls = remapClass(cat->cls);
if (!cls) { // Category's target class is missing (probably weak-linked). // Disavow any knowledge of this category. catlist[i] = nil; if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; }
// Process this category. // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if // the class is realized. bool classExists = NO; if (cat->instanceMethods || cat->protocols || cat->instanceProperties) { addUnattachedCategoryForClass(cat, cls, hi); if (cls->isRealized()) { remethodizeClass(cls); classExists = YES; } if (PrintConnecting) { _objc_inform("CLASS: found category -%s(%s) %s", cls->nameForLogging(), cat->name, classExists ? "on existing class" : ""); } }
if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { addUnattachedCategoryForClass(cat, cls->ISA(), hi); if (cls->ISA()->isRealized()) { remethodizeClass(cls->ISA()); } if (PrintConnecting) { _objc_inform("CLASS: found category +%s(%s)", cls->nameForLogging(), cat->name); } } } }
/*********************************************************************** * remethodizeClass * Attach outstanding categories to an existing class. * Fixes up cls's method list, protocol list, and property list. * Updates method caches for cls and its subclasses. * Locking: runtimeLock must be held by the caller **********************************************************************/ staticvoidremethodizeClass(Class cls) { category_list *cats; bool isMeta;
runtimeLock.assertLocked();
isMeta = cls->isMetaClass();
// Re-methodizing: check for more categories if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) { if (PrintConnecting) { _objc_inform("CLASS: attaching categories to class '%s' %s", cls->nameForLogging(), isMeta ? "(meta)" : ""); }
// Attach method lists and properties and protocols from categories to a class. // Assumes the categories in cats are all loaded and sorted by load order, // oldest categories first. staticvoid attachCategories(Class cls, category_list *cats, bool flush_caches) { if (!cats) return; if (PrintReplacedMethods) printReplacements(cls, cats);
// Count backwards through cats to get newest categories first int mcount = 0; int propcount = 0; int protocount = 0; int i = cats->count; bool fromBundle = NO; while (i--) { auto& entry = cats->list[i]; // 遍历每个分类