class_addMethod 给一个类添加方法
正常添加一个继承链中不存在的方法, 结果能够正常使用
如果这个类本身就有该方法的申明和实现则添加失败
如果这个类本身仅仅有该方法的申明那么是可以添加成功的
如果这个类本身仅仅有该方法的实现则会添加失败(预料之中,因为所谓申明仅仅是编译器的事,编译完也就没有.h的事了)
如果这个类没有该方法,但是父类有呢?结果是父类不会影响到子类添加方法的结果, 依然可以添加成功
源码分析
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
if (!cls) return NO;
mutex_locker_t lock(runtimeLock);
return ! addMethod(cls, name, imp, types ?: "", NO);
}
static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)
{
IMP result = nil;
// 加锁
runtimeLock.assertLocked();
// 检测该cls是否存在
checkIsKnownClass(cls);
// 方法签名不可为空
assert(types);
// 类必须是初始化后的
assert(cls->isRealized());
// 根据 方法名去cls这个类(不沿着继承链向上查询)查询有没有对应的方法实现
method_t *m;
if ((m = getMethodNoSuper_nolock(cls, name))) {
// 如果有的话, 因为replace传的是NO, 也不会替换原来实现
if (!replace) {
result = m->imp;
} else {
result = _method_setImplementation(cls, m, imp);
}
} else {
// 没有则生成一个新的方法并放在cls的方法列表最后
method_list_t *newlist;
// 1.开辟空间
newlist = (method_list_t *)calloc(sizeof(*newlist), 1);
// 2.初始化
newlist->entsizeAndFlags =
(uint32_t)sizeof(method_t) | fixed_up_method_list;
newlist->count = 1;
newlist->first.name = name;
newlist->first.types = strdupIfMutable(types);
newlist->first.imp = imp;
// 3.准备添加
prepareMethodLists(cls, &newlist, 1, NO, NO);
// 4.添加
cls->data()->methods.attachLists(&newlist, 1);
flushCaches(cls);
result = nil;
}
return result;
}
method_setImplementation 修改一个方法的实现部分
IMP method_setImplementation(Method m, IMP imp)
{
// 可以看出来修改一个方法的实现, 是针对Method这个结构体本身的行为
mutex_locker_t lock(runtimeLock);
return _method_setImplementation(Nil, m, imp);
}
static IMP _method_setImplementation(Class cls, method_t *m, IMP imp)
{
// 加锁
runtimeLock.assertLocked();
// 判空
if (!m) return nil;
if (!imp) return nil;
// 直接method_t这个结构体的imp成员指向了新的imp
IMP old = m->imp;
m->imp = imp;
flushCaches(cls);
updateCustomRR_AWZ(cls, m);
return old;
}
method_exchangeImplementations 交换两个方法的实现
void method_exchangeImplementations(Method m1, Method m2)
{
// 判空
if (!m1 || !m2) return;
// 加锁
mutex_locker_t lock(runtimeLock);
// 直接Method这个结构体的imp成员指向进行了交换就完事了
IMP m1_imp = m1->imp;
m1->imp = m2->imp;
m2->imp = m1_imp;
flushCaches(nil);
updateCustomRR_AWZ(nil, m1);
updateCustomRR_AWZ(nil, m2);
}
method_getImplementation 直接返回了Method这个结构体的imp
IMP method_getImplementation(Method m)
{
return m ? m->imp : nil;
}
class_getMethodImplementation 获取一个类的对应方法名的IMP
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
imp = lookUpImpOrNil(cls, sel, nil,
YES/*initialize*/, YES/*cache*/, YES/*resolver*/);
// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward;
}
return imp;
}
IMP lookUpImpOrNil(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
if (imp == _objc_msgForward_impcache) return nil;
else return imp;
}
// 执行查找imp和转发的代码
IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
IMP imp = nil;
bool triedResolver = NO;
runtimeLock.assertUnlocked();
// 如果cache是YES,则从缓存中查找IMP。如果是从cache3函数进来,则不会执行cache_getImp()函数
if (cache) {
// 通过cache_getImp函数查找IMP,查找到则返回IMP并结束调用
imp = cache_getImp(cls, sel);
if (imp) return imp;
}
runtimeLock.read();
// 判断类是否已经被创建,如果没有被创建,则将类实例化
if (!cls->isRealized()) {
// 对类进行实例化操作
realizeClass(cls);
}
// 第一次调用当前类的话,执行initialize的代码
if (initialize && !cls->isInitialized()) {
// 对类进行初始化,并开辟内存空间
_class_initialize (_class_getNonMetaClass(cls, inst));
}
retry:
runtimeLock.assertReading();
// 尝试获取这个类的缓存
imp = cache_getImp(cls, sel);
if (imp) goto done;
{
// 如果没有从cache中查找到,则从方法列表中获取Method
Method meth = getMethodNoSuper_nolock(cls, sel);
if (meth) {
// 如果获取到对应的Method,则加入缓存并从Method获取IMP
log_and_fill_cache(cls, meth->imp, sel, inst, cls);
imp = meth->imp;
goto done;
}
}
{
unsigned attempts = unreasonableClassCount();
// 循环获取这个类的缓存IMP 或 方法列表的IMP
for (Class curClass = cls->superclass;
curClass != nil;
curClass = curClass->superclass)
{
if (--attempts == 0) {
_objc_fatal("Memory corruption in class list.");
}
// 获取父类缓存的IMP
imp = cache_getImp(curClass, sel);
if (imp) {
if (imp != (IMP)_objc_msgForward_impcache) {
// 如果发现父类的方法,并且不再缓存中,在下面的函数中缓存方法
log_and_fill_cache(cls, imp, sel, inst, curClass);
goto done;
}
else {
break;
}
}
// 在父类的方法列表中,获取method_t对象。如果找到则缓存查找到的IMP
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
imp = meth->imp;
goto done;
}
}
}
// 如果没有找到,则尝试动态方法解析
if (resolver && !triedResolver) {
runtimeLock.unlockRead();
_class_resolveMethod(cls, sel, inst);
runtimeLock.read();
triedResolver = YES;
goto retry;
}
// 如果没有IMP被发现,并且动态方法解析也没有处理,则进入消息转发阶段
imp = (IMP)_objc_msgForward_impcache;
cache_fill(cls, sel, imp, inst);
done:
runtimeLock.unlockRead();
return imp;
}
class_replaceMethod 将一个类的原有方法用新方法进行替换,如果原有方法为空,则直接调用class_addMethod将新方法添加上
IMP _Nullable class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
{
if (!cls) return nil;
mutex_locker_t lock(runtimeLock);
return addMethod(cls, name, imp, types ?: "", YES);
}
static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)
{
IMP result = nil;
// 加锁
runtimeLock.assertLocked();
// 检测该cls是否存在
checkIsKnownClass(cls);
// 方法签名不可为空
assert(types);
// 类必须是初始化后的
assert(cls->isRealized());
// 根据 方法名去cls这个类(不沿着继承链向上查询)查询有没有对应的方法实现
method_t *m;
if ((m = getMethodNoSuper_nolock(cls, name))) {
// 如果有的话, 因为replace传的是YES, 会替换原来实现
if (!replace) {
result = m->imp;
} else {
result = _method_setImplementation(cls, m, imp);
}
} else {
// 没有则生成一个新的方法并放在cls的方法列表最后
method_list_t *newlist;
// 1.开辟空间
newlist = (method_list_t *)calloc(sizeof(*newlist), 1);
// 2.初始化
newlist->entsizeAndFlags =
(uint32_t)sizeof(method_t) | fixed_up_method_list;
newlist->count = 1;
newlist->first.name = name;
newlist->first.types = strdupIfMutable(types);
newlist->first.imp = imp;
// 3.准备添加
prepareMethodLists(cls, &newlist, 1, NO, NO);
// 4.添加
cls->data()->methods.attachLists(&newlist, 1);
flushCaches(cls);
result = nil;
}
return result;
}