日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Objective-C method及相关方法分析

發布時間:2024/4/17 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Objective-C method及相关方法分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

## Objective-C method及相關方法分析

轉載請注名出處 [http://blog.csdn.net/uxyheaven](http://blog.csdn.net/uxyheaven/article/details/38120335)

本篇文章將探究一下objc里的關于方法的函數是怎樣實現的

首先看下方法的定義, Method 是一個objc_method結構體

objc_method


objc_method 是類的一個方法的描寫敘述


定義例如以下

typedef struct objc_method *Method;struct objc_method {SEL method_name; // 方法名稱char *method_typesE; // 參數和返回類型的描寫敘述字串IMP method_imp; // 方法的詳細的實現的指針 }

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. 找轉發if (!meth && withResolver) meth = _class_resolveMethod(cls, sel);return meth; }

IMP class_getMethodImplementation(Class cls, SEL name)


返回cls的name方法的調用地址


定義例如以下
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. 假設還是找不到就轉發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; }
不同的類能夠有同樣的方法名,方法鏈表中依據方法名去查找詳細的方法實現的.
IMP 是一個函數指針, 這個被指向的函數包括一個接收消息的對象id(self指針), 調用方法的選標SEL(方法名), 及不定個數的方法參數, 并返回一個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 {// 代替, 設置 cls 的 m 方法實現為 impresult = _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已經存在這種方法的時候加入是失敗的


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); }
淚目, 這里就是直接設置replace == YES.


void method_exchangeImplementations(Method m1_gen, Method m2_gen)


交換2個方法的實現指針
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替換,會把父類替的方法替換掉,這顯然不是我們想要的.所以呢,我們的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的實現指針


代碼例如以下, 沒什么好說的,事實上就是返回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)


設置方法的新的實現指針, 返回舊的實現指針
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;}// 替換方法的實現指針IMP 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的參數和返回值的描寫敘述的字串


這個就是直接返回m->types

轉載于:https://www.cnblogs.com/brucemengbm/p/7016320.html

總結

以上是生活随笔為你收集整理的Objective-C method及相关方法分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。