iOS runtime 筆記二 — Method 介紹及 swizzle

參考內(nèi)容

Objective-C Runtime 運(yùn)行時(shí)之三:方法與消息

方法中 SEL, IMP, Method 的定義與關(guān)系

![示意圖](http://upload-images.jianshu.io/upload_images/1180547-f7906aa5b8893729.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

SEL

  • 代表方法的名稱。僅以名字來識(shí)別。
  • 不論兩個(gè)類是否存在依存關(guān)系,只要他們擁有相同的方法名,那么他們的SEL都是相同的。比如,有n個(gè)viewcontroller頁面,每個(gè)頁面都有一個(gè)viewdidload,每個(gè)頁面的載入,肯定都是不盡相同的。但是我們可以通過打印,觀察發(fā)現(xiàn),這些viewdidloadSEL都是同一個(gè):
SEL sel = @selector(methodName);
NSLog(@"address = %p",sel);// log輸出為 address = 0x100002d72
  • 因此類方法定義時(shí),盡量不要用相同的名字,就算是變量類型不同也不行。否則會(huì)引起重復(fù),例如:
-(void)setWidth:(int)width;
-(void)setWidth:(double)width;

IMP

  • 定義:
id (*IMP)(id, SEL, ...)

個(gè)人理解:

  • SEL只提供一個(gè)名字,但是至于這個(gè)名字屬于誰,并不知道。A類和B類的SEL實(shí)際實(shí)現(xiàn)IMP是不一樣的。IMP其實(shí)是implementation的縮寫。
  • IMP定義中存在兩個(gè)參數(shù),id 即為指向self的指針。SEL就是上面說的方法名
  • 綜合來看,IMP可以理解為,我知道有一個(gè)方法,是SEL告訴我的,但是這是哪個(gè)類的里面具體的實(shí)現(xiàn)方法,需要id告訴我。兩者確定后,我就可以獲得某個(gè)指定的方法的內(nèi)容了IMP相當(dāng)于是函數(shù)指針。

Method

  • 我們可以看到該結(jié)構(gòu)體中包含一個(gè)SEL和IMP,實(shí)際上相當(dāng)于在SEL和IMP之間作了一個(gè)映射。有了SEL,我們便可以找到對(duì)應(yīng)的IMP,從而調(diào)用方法的實(shí)現(xiàn)代碼。具體操作流程我們將在下面討論。
  • 個(gè)人理解,Method相當(dāng)于是把二者綜合在一起,是一個(gè)完整的,我們傳統(tǒng)意義上理解的方法

Method 方法及說明

// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );

// 獲取實(shí)例方法
Method class_getInstanceMethod ( Class cls, SEL name );

// 獲取類方法
Method class_getClassMethod ( Class cls, SEL name );

// 獲取所有方法的數(shù)組
Method * class_copyMethodList ( Class cls, unsigned int *outCount );

// 替代方法的實(shí)現(xiàn)
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );

// 返回方法的具體實(shí)現(xiàn)
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );

// 類實(shí)例是否響應(yīng)指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );

說明

  • class_addMethod的實(shí)現(xiàn)會(huì)覆蓋父類的方法實(shí)現(xiàn),但不會(huì)取代本類中已存在的實(shí)現(xiàn),如果本類中包含一個(gè)同名的實(shí)現(xiàn),則函數(shù)會(huì)返回NO。如果要修改已存在實(shí)現(xiàn),可以使用method_setImplementation 一個(gè)Objective-C方法是一個(gè)簡單的C函數(shù),它至少包含兩個(gè)參數(shù)–self_cmd。所以,我們的實(shí)現(xiàn)函數(shù)(IMP參數(shù)指向的函數(shù))至少需要兩個(gè)參數(shù)

  • class_getInstanceMethodclass_getClassMethod函數(shù),與class_copyMethodList不同的是,這兩個(gè)函數(shù)都會(huì)去搜索父類的實(shí)現(xiàn)。

  • class_copyMethodList函數(shù),返回包含所有實(shí)例方法的數(shù)組,如果需要獲取類方法,則可以使用class_copyMethodList(object_getClass(cls), &count)(一個(gè)類的實(shí)例方法是定義在元類里面)。該列表不包含父類實(shí)現(xiàn)的方法。outCount參數(shù)返回方法的個(gè)數(shù)。在獲取到列表后,我們需要使用free()方法來釋放它。

  • class_replaceMethod函數(shù),該函數(shù)的行為可以分為兩種:如果類中不存在name指定的方法,則類似于class_addMethod函數(shù)一樣會(huì)添加方法;如果類中已存在name指定的方法,則類似于method_setImplementation一樣替代原方法的實(shí)現(xiàn)。

  • class_getMethodImplementation函數(shù),該函數(shù)在向類實(shí)例發(fā)送消息時(shí)會(huì)被調(diào)用,并返回一個(gè)指向方法實(shí)現(xiàn)函數(shù)的指針。這個(gè)函數(shù)會(huì)比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函數(shù)指針可能是一個(gè)指向runtime內(nèi)部的函數(shù),而不一定是方法的實(shí)際實(shí)現(xiàn)。例如,如果類實(shí)例無法響應(yīng)selector,則返回的函數(shù)指針將是運(yùn)行時(shí)消息轉(zhuǎn)發(fā)機(jī)制的一部分。

  • class_respondsToSelector函數(shù),我們通常使用NSObject類的respondsToSelector:instancesRespondToSelector:方法來達(dá)到相同目的。

示例,實(shí)現(xiàn) method swizzle

用runtime + category 實(shí)現(xiàn)

注釋.png

runtimetypes的說明

const char *types一個(gè)定義該函數(shù)返回值類型和參數(shù)類型的字符串
舉例說明

  • 函數(shù)原型
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
  • 說明
class_addMethod([TestClass class], @selector(ocMethod:), (IMP)testFunc, "i@:@");
* `i`表示方法的返回類型,下面是`dash`中的截圖

函數(shù)說明.png

* 第一個(gè)@是必須有的,表示self. 也就是說,上面說的返回類型+@是必備的。
* :@ 表示傳入的參數(shù)。如果有兩個(gè)參數(shù),就是:@@.可參見下面的代碼

BOOL class_addMethod(Class cls,SEL name,IMP imp,    const char *types)   

/**
  * 一個(gè)參數(shù)
  *
  */

int cfunction(id self, SEL _cmd, NSString *str) {
    NSLog(@"%@", str);
    return10;//隨便返回個(gè)值
}

-(void) oneParam {  
    TestClass *instance = [[TestClassalloc]init];
    //    方法添加
    class_addMethod([TestClassclass],@selector(ocMethod:), (IMP)cfunction,"i@:@");
    
    if ([instance respondsToSelector:@selector(ocMethod:)]) {
        NSLog(@"Yes, instance respondsToSelector:@selector(ocMethod:)");
    } else
        NSLog(@"Sorry");
    
    int a = (int)[instance ocMethod:@"我是一個(gè)OC的method,C函數(shù)實(shí)現(xiàn)"];
    NSLog(@"a:%d", a);
}

 /**
  * 兩個(gè)參數(shù)
  *
  */

int cfunctionA(id self, SEL _cmd, NSString *str, NSString *str1) {
    NSLog(@"%@-%@", str, str1);
    return20;//隨便返回個(gè)值
}
-(void) twoParam {  
    TestClass *instance = [[TestClass alloc]init];   
    class_addMethod([TestClass class],@selector(ocMethodA::), (IMP)cfunctionA,"i@:@@");
    
    if ([instance respondsToSelector:@selector(ocMethodA::)]) {
        NSLog(@"Yes, instance respondsToSelector:@selector(ocMethodA::)");
    } else
        NSLog(@"Sorry");
    int a = (int)[instance ocMethodA:@"我是一個(gè)OC的method,C函數(shù)實(shí)現(xiàn)" :@"-----我是第二個(gè)參數(shù)"];
    NSLog(@"a:%d", a);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,860評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,025評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,421評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,642評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,177評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,970評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,157評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,410評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評(píng)論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,896評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,157評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,753評(píng)論 0 9
  • 我們常常會(huì)聽說 Objective-C 是一門動(dòng)態(tài)語言,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,227評(píng)論 0 7
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 772評(píng)論 0 1
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,579評(píng)論 33 466
  • 官方源碼下載地址:http://download.csdn.net/detail/liangliang103377...
    有一種再見叫青春閱讀 1,997評(píng)論 2 11