转载请注名出处 http://blog.csdn.net/uxyheaven
本篇文章将探究一下objc里的关于方法的函数是如何实现的
首先看下方法的定义, Method 是一个objc_method结构体
objc_method 是类的一个方法的描述
定义如下
Method class_getInstanceMethod(Class cls, SEL sel) { if (!cls || !sel) return NULL; return look_up_method(cls, sel, YES/*cache*/, YES/*resolver*/); } static Method look_up_method(Class cls, SEL sel, BOOL withCache, BOOL withResolver) { Method meth = NULL; // 1. 找缓存,有过有就返回 if (withCache) { meth = _cache_getMethod(cls, sel, &_objc_msgForward_internal); if (meth == (Method)1) { // Cache contains forward:: . Stop searching. return NULL; } } // 2. 找自身 if (!meth) meth = _class_getMethod(cls, sel); // 3. 找转发 if (!meth && withResolver) meth = _class_resolveMethod(cls, sel); return meth; }
返回cls的name方法的调用地址
定义如下
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) { if (!cls) return NO; rwlock_write(&runtimeLock); IMP old = addMethod(newcls(cls), name, imp, types ?: "", NO); rwlock_unlock_write(&runtimeLock); return old ? NO : YES; } static IMP addMethod(class_t *cls, SEL name, IMP imp, const char *types, BOOL replace) { IMP result = NULL; rwlock_assert_writing(&runtimeLock); assert(types); assert(isRealized(cls)); method_t *m; // 1. 在自己的类的方法列表里找这个方法 if ((m = getMethodNoSuper_nolock(cls, name))) { // already exists if (!replace) { // 不取代, 返回 m->imp result = _method_getImplementation(m); } else { // 取代, 设置 cls 的 m 方法实现为 imp result = _method_setImplementation(cls, m, imp); } } else { // fixme optimize // 2. 建立一个method_list_t节点 method_list_t *newlist; newlist = (method_list_t *)_calloc_internal(sizeof(*newlist), 1); newlist->entsize_NEVER_USE = (uint32_t)sizeof(method_t) | fixed_up_method_list; newlist->count = 1; newlist->first.name = name; newlist->first.types = strdup(types); if (!ignoreSelector(name)) { newlist->first.imp = imp; } else { newlist->first.imp = (IMP)&_objc_ignored_method; } // 3. 把newlist加到cls的方法列表里 BOOL vtablesAffected = NO; attachMethodLists(cls, &newlist, 1, NO, &vtablesAffected); // 4. 刷新cls缓存 flushCaches(cls); if (vtablesAffected) flushVtables(cls); result = NULL; } return result; }
我们用class_addMethod时, replace == NO, 所以cls已经存在这个方法的时候添加是失败的
替换cls的name方法的指针
void method_exchangeImplementations(Method m1_gen, Method m2_gen) { method_t *m1 = newmethod(m1_gen); method_t *m2 = newmethod(m2_gen); if (!m1 || !m2) return; rwlock_write(&runtimeLock); if (ignoreSelector(m1->name) || ignoreSelector(m2->name)) { // Ignored methods stay ignored. Now they're both ignored. m1->imp = (IMP)&_objc_ignored_method; m2->imp = (IMP)&_objc_ignored_method; rwlock_unlock_write(&runtimeLock); return; } // 交换2个方法的实现指针 IMP m1_imp = m1->imp; m1->imp = m2->imp; m2->imp = m1_imp; if (vtable_containsSelector(m1->name) || vtable_containsSelector(m2->name)) { // Don't know the class - will be slow if vtables are affected // fixme build list of classes whose Methods are known externally? flushVtables(NULL); } // fixme catch NSObject changing to custom RR // cls->setCustomRR(); // fixme update monomorphism if necessary rwlock_unlock_write(&runtimeLock); }
其实这里有个坑, Method是怎么来的呢, 通过class_getInstanceMethod,如果子类没有的话,会返回父类的方法, 如果这个时候在用method_exchangeImplementations替换,会把父类替的方法替换掉,这显然不是我们想要的.所以呢,我们的移魂大发通常是这么写
IMP method_getImplementation(Method m) { return _method_getImplementation(newmethod(m)); } static IMP _method_getImplementation(method_t *m) { if (!m) return NULL; return m->imp; }
设置方法的新的实现指针, 返回旧的实现指针
const char *method_getTypeEncoding(Method m) { if (!m) return NULL; return newmethod(m)->types; }
原文:http://blog.csdn.net/uxyheaven/article/details/40350911