方法调用
image.png源码(主干部分)
static void
attachCategories(Class cls, category_list *cats, bool flush_caches)
{
bool isMeta = cls->isMetaClass();
method_list_t **mlists = (method_list_t **) malloc(cats->count * sizeof(*mlists));
int mcount = 0;
int i = cats->count;
bool fromBundle = NO;
//反向遍历,将分类的方法添加到mlist数组。
while (i--) {
auto& entry = cats->list[i];
method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
if (mlist) {
mlists[mcount++] = mlist;
}
}
//获取class的相关信息,其中包含方法列表
auto rw = cls->data();
//在class的方法列表上,拼接上分类的方法列表
//调用该方法后,分类方法才真正添加到class的方法列表中。
rw->methods.attachLists(mlists, mcount);
}
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
//原有方法数量
uint32_t oldCount = array()->count;
//新增方法数量
uint32_t newCount = oldCount + addedCount;
//分配方法的内存空间
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
array()->count = newCount;
//内存移动。将类的原有方法,移动到分类方法之后。
//array()->lists,迭代器里的List **lists,表示未拼接分类方法的二维数组。
//addedCount是一个uint32_t(4Byte),array()->lists是指针(4Byte)的数组
//sizeof(array()->lists[0]) = sizeof(指针)
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
//内存复制。将新增的分类方法,拷贝到类的方法列表中,从首地址开始。
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];
}
else {
// 1 list -> many lists
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)malloc(array_t::byteSize(newCount)));
array()->count = newCount;
//将class的原有方法,移动到分类方法之后。
if (oldList) array()->lists[addedCount] = oldList;
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
}
总结
0.分类的方法,是在编译的时候添加的,还是运行时添加?
运行时
1.为什么分类方法会覆盖掉原有方法?
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
因为分类的方法,在方法列表中的位置,在原有方法之前。实际上原有方法依旧存在,没有被真正的覆盖。
2.为什么分类中的同名方法,最后编译的分类生效?
因为分类方法是反向遍历的,最后编译的方法,它在方法列表中的位置越靠前。实际上所有的同名方法都存在。
网友评论