Objective-C method及相关方法分析
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                Objective-C method及相关方法分析
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.                        
                                ## Objective-C method及相關(guān)方法分析
 轉(zhuǎn)載請注名出處 [http://blog.csdn.net/uxyheaven](http://blog.csdn.net/uxyheaven/article/details/38120335)本篇文章將探究一下objc里的關(guān)于方法的函數(shù)是怎樣實現(xiàn)的
首先看下方法的定義, Method 是一個objc_method結(jié)構(gòu)體
objc_method
objc_method 是類的一個方法的描寫敘述
定義例如以下
typedef struct objc_method *Method;struct objc_method {SEL method_name; // 方法名稱char *method_typesE; // 參數(shù)和返回類型的描寫敘述字串IMP method_imp; // 方法的詳細的實現(xiàn)的指針 }
Method class_getInstanceMethod(Class aClass, SEL aSelector)
返回aClass的名為aSelector的方法
定義例如以下
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. 找轉(zhuǎn)發(fā)if (!meth && withResolver) meth = _class_resolveMethod(cls, sel);return meth; }
IMP class_getMethodImplementation(Class cls, SEL name)
返回cls的name方法的調(diào)用地址
定義例如以下
IMP class_getMethodImplementation(Class cls, SEL sel) {IMP imp;if (!cls || !sel) return NULL;imp = lookUpMethod(cls, sel, YES/*initialize*/, YES/*cache*/);// Translate forwarding function to C-callable external versionif (imp == (IMP)&_objc_msgForward_internal) {return (IMP)&_objc_msgForward;}return imp; }PRIVATE_EXTERN IMP lookUpMethod(Class cls, SEL sel, BOOL initialize, BOOL cache) {Class curClass;IMP methodPC = NULL;Method meth;BOOL triedResolver = NO;// Optimistic cache lookup// 1. 先找下緩存if (cache) {methodPC = _cache_getImp(cls, sel);if (methodPC) return methodPC; }// realize, +initialize, and any special early exit// 2. 初始化下這個類,為接下來做準備methodPC = prepareForMethodLookup(cls, sel, initialize);if (methodPC) return methodPC;// The lock is held to make method-lookup + cache-fill atomic // with respect to method addition. Otherwise, a category could // be added but ignored indefinitely because the cache was re-filled // with the old value after the cache flush on behalf of the category.retry:lockForMethodLookup();// Ignore GC selectorsif (ignoreSelector(sel)) {methodPC = _cache_addIgnoredEntry(cls, sel);goto done;}// Try this class's cache.// 3. 先試著找緩存methodPC = _cache_getImp(cls, sel);if (methodPC) goto done;// Try this class's method lists.// 4. 找自己的method列表meth = _class_getMethodNoSuper_nolock(cls, sel);if (meth) {log_and_fill_cache(cls, cls, meth, sel);methodPC = method_getImplementation(meth);goto done;}// Try superclass caches and method lists.// 5. 找父類的緩存和method列表curClass = cls;while ((curClass = _class_getSuperclass(curClass))) {// Superclass cache.meth = _cache_getMethod(curClass, sel, &_objc_msgForward_internal);if (meth) {if (meth != (Method)1) {// Found the method in a superclass. Cache it in this class.log_and_fill_cache(cls, curClass, meth, sel);methodPC = method_getImplementation(meth);goto done;}else {// Found a forward:: entry in a superclass.// Stop searching, but don't cache yet; call method // resolver for this class first.break;}}// Superclass method list.meth = _class_getMethodNoSuper_nolock(curClass, sel);if (meth) {log_and_fill_cache(cls, curClass, meth, sel);methodPC = method_getImplementation(meth);goto done;}}// No implementation found. Try method resolver once.// 6. 假設(shè)還是找不到就轉(zhuǎn)發(fā)if (!triedResolver) {unlockForMethodLookup();_class_resolveMethod(cls, sel);// Don't cache the result; we don't hold the lock so it may have // changed already. Re-do the search from scratch instead.triedResolver = YES;goto retry;}// No implementation found, and method resolver didn't help. // Use forwarding._cache_addForwardEntry(cls, sel);methodPC = &_objc_msgForward_internal;done:unlockForMethodLookup();// paranoia: look for ignored selectors with non-ignored implementationsassert(!(ignoreSelector(sel) && methodPC != (IMP)&_objc_ignored_method));return methodPC; }
不同的類能夠有同樣的方法名,方法鏈表中依據(jù)方法名去查找詳細的方法實現(xiàn)的.
IMP 是一個函數(shù)指針, 這個被指向的函數(shù)包括一個接收消息的對象id(self指針), 調(diào)用方法的選標SEL(方法名), 及不定個數(shù)的方法參數(shù), 并返回一個id。
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
給cls加入一個新的方法,若干cls存在這種方法則返回失敗
以下來看代碼
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 existsif (!replace) {// 不代替, 返回 m->impresult = _method_getImplementation(m);} else {// 代替, 設(shè)置 cls 的 m 方法實現(xiàn)為 impresult = _method_setImplementation(cls, m, imp);}} else {// fixme optimize// 2. 建立一個method_list_t節(jié)點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已經(jīng)存在這種方法的時候加入是失敗的
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
替換cls的name方法的指針
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) {if (!cls) return NULL;return _class_addMethod(cls, name, imp, types, YES); }
淚目, 這里就是直接設(shè)置replace == YES.
void method_exchangeImplementations(Method m1_gen, Method m2_gen)
交換2個方法的實現(xiàn)指針
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個方法的實現(xiàn)指針I(yè)MP 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,假設(shè)子類沒有的話,會返回父類的方法, 假設(shè)這個時候在用method_exchangeImplementations替換,會把父類替的方法替換掉,這顯然不是我們想要的.所以呢,我們的method swizzle一般是這么寫
static void XY_swizzleInstanceMethod(Class c, SEL original, SEL replacement) {Method a = class_getInstanceMethod(c, original);Method b = class_getInstanceMethod(c, replacement);if (class_addMethod(c, original, method_getImplementation(b), method_getTypeEncoding(b))){class_replaceMethod(c, replacement, method_getImplementation(a), method_getTypeEncoding(a));}else{method_exchangeImplementations(a, b); } }
IMP method_getImplementation(Method method)
返回method的實現(xiàn)指針
代碼例如以下, 沒什么好說的,事實上就是返回method->imp
IMP method_getImplementation(Method m) {return _method_getImplementation(newmethod(m)); }static IMP _method_getImplementation(method_t *m) {if (!m) return NULL;return m->imp; }
IMP method_setImplementation(Method method, IMP imp)
設(shè)置方法的新的實現(xiàn)指針, 返回舊的實現(xiàn)指針
IMP method_setImplementation(Method m, IMP imp) {// Don't know the class - will be slow if vtables are affected// fixme build list of classes whose Methods are known externally?IMP result;rwlock_write(&runtimeLock);result = _method_setImplementation(Nil, newmethod(m), imp);rwlock_unlock_write(&runtimeLock);return result; }static IMP _method_setImplementation(class_t *cls, method_t *m, IMP imp) {rwlock_assert_writing(&runtimeLock);if (!m) return NULL;if (!imp) return NULL;if (ignoreSelector(m->name)) {// Ignored methods stay ignoredreturn m->imp;}// 替換方法的實現(xiàn)指針I(yè)MP old = _method_getImplementation(m);m->imp = imp;// No cache flushing needed - cache contains Methods not IMPs.if (vtable_containsSelector(newmethod(m)->name)) {// Will be slow if cls is NULL (i.e. unknown)// fixme build list of classes whose Methods are known externally?
flushVtables(cls); } // fixme catch NSObject changing to custom RR // cls->setCustomRR(); // fixme update monomorphism if necessary return old; }
method_getTypeEncoding(Method m)
返回方法m的參數(shù)和返回值的描寫敘述的字串
這個就是直接返回m->types
轉(zhuǎn)載于:https://www.cnblogs.com/brucemengbm/p/7016320.html
總結(jié)
以上是生活随笔為你收集整理的Objective-C method及相关方法分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: conductor任务域
- 下一篇: 如何正确的终止正在运行的子线程
