1. API
/** * Adds a new method to a class with a given name and implementation. * * @param cls The class to which to add a method. * @param name A selector that specifies the name of the method being added. * @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd. * @param types An array of characters that describe the types of the arguments to the method. * * @return YES if the method was added successfully, otherwise NO * (for example, the class already contains a method implementation with that name). * * @note class_addMethod will add an override of a superclass's implementation, * but will not replace an existing implementation in this class. * To change an existing implementation, use method_setImplementation. */ OBJC_EXPORT BOOL class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
- 由API知道,当方法添加成功的时返回YES, 方法添加失败时返回NO(当方法已经存在的情况下会返回NO)
- 该方法会添加父类实现的方法
- 不会添加本类中已经存在的IMP,如要更改本类中已经存在的IMP。需要用
请使用method_setImplementation
2. Runtime 源码
objc-runtime-new.mm
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); }
/********************************************************************** * addMethod * fixme * Locking: runtimeLock must be held by the caller **********************************************************************/ static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace) { IMP result = nil; runtimeLock.assertLocked(); checkIsKnownClass(cls); ASSERT(types); ASSERT(cls->isRealized()); method_t *m; if ((m = getMethodNoSuper_nolock(cls, name))) { // already exists if (!replace) { result = m->imp(false); } else { result = _method_setImplementation(cls, m, imp); } } else { // fixme optimize method_list_t *newlist; newlist = (method_list_t *)calloc(method_list_t::byteSize(method_t::bigSize, 1), 1); newlist->entsizeAndFlags = (uint32_t)sizeof(struct method_t::big) | fixed_up_method_list; newlist->count = 1; auto &first = newlist->begin()->big(); first.name = name; first.types = strdupIfMutable(types); first.imp = imp; addMethods_finish(cls, newlist); result = nil; } return result; }
由源码可以看到,Runtime先查找该类在父类中是否存在,若存在,生成一个新方法(重写)
若不存在,生成新的method_list,并将新方法插入到新生成的method_list中,然后替换原来的method_list