staticvoidattachMethodLists(Class cls, method_list_t **addedLists, int addedCount,
bool baseMethods, bool methodsFromBundle,
bool flushCaches) {
rwlock_assert_writing(&runtimeLock);
// Don't scan redundantly
bool scanForCustomRR =!UseGC &&!cls->hasCustomRR();
bool scanForCustomAWZ =!UseGC &&!cls->hasCustomAWZ();
// There exist RR/AWZ special cases for some class's base methods.
// But this code should never need to scan base methods for RR/AWZ:
// default RR/AWZ cannot be set before setInitialized().
// Therefore we need not handle any special cases here.
if (baseMethods) {
assert(!scanForCustomRR &&!scanForCustomAWZ);
}
// Method list array is nil-terminated.
// Some elements of lists are nil; we must filter them out.
method_list_t *oldBuf[2];
method_list_t **oldLists;
int oldCount =0;
if (cls->data()->flags & RW_METHOD_ARRAY) {
oldLists = cls->data()->method_lists;
} else {
oldBuf[0] = cls->data()->method_list;
oldBuf[1] = nil;
oldLists = oldBuf;
}
if (oldLists) {
while (oldLists[oldCount]) oldCount++;
}
int newCount = oldCount;
for (int i =0; i < addedCount; i++) {
if (addedLists[i]) newCount++; // only non-nil entries get added
}
method_list_t *newBuf[2];
method_list_t **newLists;
if (newCount >1) {
newLists = (method_list_t **)
_malloc_internal((1+ newCount) *sizeof(*newLists));
} else {
newLists = newBuf;
}
// Add method lists to array.
// Reallocate un-fixed method lists.
// The new methods are PREPENDED to the method list array.
newCount =0;
int i;
for (i =0; i < addedCount; i++) {
method_list_t *mlist = addedLists[i];
if (!mlist) continue;
// Fixup selectors if necessary
if (!isMethodListFixedUp(mlist)) {
mlist = fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
}
// Scan for method implementations tracked by the class's flags
if (scanForCustomRR && methodListImplementsRR(mlist)) {
cls->setHasCustomRR();
scanForCustomRR = false;
}
if (scanForCustomAWZ && methodListImplementsAWZ(mlist)) {
cls->setHasCustomAWZ();
scanForCustomAWZ = false;
}
// Update method caches
if (flushCaches) {
cache_eraseMethods(cls, mlist);
}
// Fill method list array
newLists[newCount++] = mlist;
}
// Copy old methods to the method list array
for (i =0; i < oldCount; i++) {
newLists[newCount++] = oldLists[i];
}
if (oldLists && oldLists != oldBuf) free(oldLists);
// nil-terminate
newLists[newCount] = nil;
if (newCount >1) {
assert(newLists != newBuf);
cls->data()->method_lists = newLists;
cls->setInfo(RW_METHOD_ARRAY);
} else {
assert(newLists == newBuf);
cls->data()->method_list = newLists[0];
assert(!(cls->data()->flags & RW_METHOD_ARRAY));
}
}
注意上面代码中注释copy old methods to the method list array,可以获知该类原有的方法被追加到了新方法列表的后面,因此可以了解如果category和原来的都由methodA方法,那newLists中肯定存在两个methodA方法。而运行时在查找类方法的时候是在方法列表中按序查找的,一旦发现对应签名的方法则就返回,因此被后置的原有方法自然而然就被方法列表前面的同签名方法所覆盖了。