iOS Runtime學(xué)習(xí)筆記(下)

方法

定義

typedef struct objc_method *Method

方法調(diào)用

1各聘、如果用實(shí)例對(duì)象調(diào)用實(shí)例方法吭历,會(huì)到實(shí)例的isa指針指向的對(duì)象(也就是類(lèi)對(duì)象)操作。

2呼渣、如果調(diào)用的是類(lèi)方法棘伴,就會(huì)到類(lèi)對(duì)象的isa指針指向的對(duì)象(也就是元類(lèi)對(duì)象)中操作。

首先屁置,在相應(yīng)操作的對(duì)象中的緩存方法列表中找調(diào)用的方法焊夸,如果找到,轉(zhuǎn)向相應(yīng)實(shí)現(xiàn)并執(zhí)行缰犁。

3淳地、如果沒(méi)找到,在相應(yīng)操作的對(duì)象中的方法列表中找調(diào)用的方法帅容,如果找到颇象,轉(zhuǎn)向相應(yīng)實(shí)現(xiàn)執(zhí)行

如果沒(méi)找到,去父類(lèi)指針?biāo)赶虻膶?duì)象中執(zhí)行1并徘,2.

4遣钳、以此類(lèi)推,如果一直到根類(lèi)還沒(méi)找到麦乞,轉(zhuǎn)向攔截調(diào)用蕴茴。

5、如果沒(méi)有重寫(xiě)攔截調(diào)用的方法姐直,程序報(bào)錯(cuò)倦淀。

重寫(xiě)父類(lèi)的方法,并沒(méi)有覆蓋掉父類(lèi)的方法声畏,只是在當(dāng)前類(lèi)對(duì)象中找到了這個(gè)方法后就不會(huì)再去父類(lèi)中找了撞叽。

如果想調(diào)用已經(jīng)重寫(xiě)過(guò)的方法的父類(lèi)的實(shí)現(xiàn)姻成,只需使用super這個(gè)編譯器標(biāo)識(shí),它會(huì)在運(yùn)行時(shí)跳過(guò)在當(dāng)前的類(lèi)對(duì)象中尋找方法的過(guò)程愿棋。

攔截調(diào)用

攔截調(diào)用就是科展,在找不到調(diào)用的方法程序崩潰之前,你有機(jī)會(huì)通過(guò)重寫(xiě)NSObject的四個(gè)方法來(lái)處理糠雨。

+ (BOOL)resolveClassMethod:(SEL)sel;

+ (BOOL)resolveInstanceMethod:(SEL)sel;

//后兩個(gè)方法需要轉(zhuǎn)發(fā)到其他的類(lèi)處理

- (id)forwardingTargetForSelector:(SEL)aSelector;

- (void)forwardInvocation:(NSInvocation *)anInvocation;

第一個(gè)方法是當(dāng)你調(diào)用一個(gè)不存在的類(lèi)方法的時(shí)候才睹,會(huì)調(diào)用這個(gè)方法,默認(rèn)返回NO甘邀,你可以加上自己的處理然后返回YES琅攘。

第二個(gè)方法和第一個(gè)方法相似,只不過(guò)處理的是實(shí)例方法鹃答。

第三個(gè)方法是將你調(diào)用的不存在的方法重定向到一個(gè)其他聲明了這個(gè)方法的類(lèi)乎澄,只需要你返回一個(gè)有這個(gè)方法的target。

第四個(gè)方法是將你調(diào)用的不存在的方法打包成NSInvocation傳給你测摔。做完你自己的處理后置济,調(diào)用invokeWithTarget:方法讓某個(gè)target觸發(fā)這個(gè)方法。

動(dòng)態(tài)添加方法

重寫(xiě)了攔截調(diào)用的方法并且返回了YES锋八,我們要怎么處理呢浙于?

有一個(gè)辦法是根據(jù)傳進(jìn)來(lái)的SEL類(lèi)型的selector動(dòng)態(tài)添加一個(gè)方法。

首先從外部隱式調(diào)用一個(gè)不存在的方法:

//隱式調(diào)用方法

[target performSelector:@selector(resolveAdd:) withObject:@"test"];

然后挟纱,在target對(duì)象內(nèi)部重寫(xiě)攔截調(diào)用的方法羞酗,動(dòng)態(tài)添加方法。

void runAddMethod(id self, SEL _cmd, NSString *string){

NSLog(@"add C IMP ", string);

}

+ (BOOL)resolveInstanceMethod:(SEL)sel{

//給本類(lèi)動(dòng)態(tài)添加一個(gè)方法

if ([NSStringFromSelector(sel) ?isEqualToString: @"resolveAdd:"]) {

? ? ?class_addMethod(self, sel, (IMP)runAddMethod, "v@:*");

}

return YES;

}

其中class_addMethod的四個(gè)參數(shù)分別是:

Class cls給哪個(gè)類(lèi)添加方法紊服,本例中是self

SEL name添加的方法檀轨,本例中是重寫(xiě)的攔截調(diào)用傳進(jìn)來(lái)的selector。

IMP imp方法的實(shí)現(xiàn)欺嗤,C方法的方法實(shí)現(xiàn)可以直接獲得参萄。如果是OC方法,可以用+ (IMP)instanceMethodForSelector:(SEL)aSelector;獲得方法的實(shí)現(xiàn)煎饼。

"v@:*"方法的簽名讹挎,代表有一個(gè)參數(shù)的方法。

方法交換

方法交換吆玖,顧名思義筒溃,就是將兩個(gè)方法的實(shí)現(xiàn)交換。例如沾乘,將A方法和B方法交換怜奖,調(diào)用A方法的時(shí)候,就會(huì)執(zhí)行B方法中的代碼翅阵,反之亦然烦周。

話不多說(shuō)尽爆,這是參考Mattt大神在NSHipster上的文章自己寫(xiě)的代碼怎顾。

#import "UIViewController+swizzling.h"

#import

@implementation UIViewController (swizzling)

//load方法會(huì)在類(lèi)第一次加載的時(shí)候被調(diào)用

//調(diào)用的時(shí)間比較靠前读慎,適合在這個(gè)方法里做方法交換

+ (void)load{

//方法交換應(yīng)該被保證,在程序中只會(huì)執(zhí)行一次

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

//獲得viewController的生命周期方法的selector

SEL systemSel = @selector(viewWillAppear:);

//自己實(shí)現(xiàn)的將要被交換的方法的selector

SEL swizzSel = @selector(swiz_viewWillAppear:);

//兩個(gè)方法的Method

Method systemMethod = class_getInstanceMethod([self class], systemSel);

Method swizzMethod = class_getInstanceMethod([self class], swizzSel);

//首先動(dòng)態(tài)添加方法槐雾,實(shí)現(xiàn)是被交換的方法夭委,返回值表示添加成功還是失敗

BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));

if (isAdd) {

//如果成功,說(shuō)明類(lèi)中不存在這個(gè)方法的實(shí)現(xiàn)

//將被交換方法的實(shí)現(xiàn)替換到這個(gè)并不存在的實(shí)現(xiàn)

class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));

}else{

//否則募强,交換兩個(gè)方法的實(shí)現(xiàn)

method_exchangeImplementations(systemMethod, swizzMethod);

}

});

}

- (void)swiz_viewWillAppear:(BOOL)animated{

//這時(shí)候調(diào)用自己株灸,看起來(lái)像是死循環(huán)

//但是其實(shí)自己的實(shí)現(xiàn)已經(jīng)被替換了

[self swiz_viewWillAppear:animated];

NSLog(@"swizzle");

}

@end

在一個(gè)自己定義的viewController中重寫(xiě)viewWillAppear

- (void)viewWillAppear:(BOOL)animated{

[super viewWillAppear:animated];

NSLog(@"viewWillAppear");

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市擎值,隨后出現(xiàn)的幾起案子慌烧,更是在濱河造成了極大的恐慌,老刑警劉巖鸠儿,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屹蚊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡进每,警方通過(guò)查閱死者的電腦和手機(jī)汹粤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)田晚,“玉大人嘱兼,你說(shuō)我怎么就攤上這事∠屯剑” “怎么了芹壕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)接奈。 經(jīng)常有香客問(wèn)我踢涌,道長(zhǎng),這世上最難降的妖魔是什么鲫趁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任斯嚎,我火速辦了婚禮,結(jié)果婚禮上挨厚,老公的妹妹穿的比我還像新娘堡僻。我一直安慰自己,他們只是感情好疫剃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布钉疫。 她就那樣靜靜地躺著,像睡著了一般巢价。 火紅的嫁衣襯著肌膚如雪牲阁。 梳的紋絲不亂的頭發(fā)上固阁,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音城菊,去河邊找鬼备燃。 笑死,一個(gè)胖子當(dāng)著我的面吹牛凌唬,可吹牛的內(nèi)容都是我干的并齐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼客税,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼况褪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起更耻,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤测垛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后秧均,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體食侮,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年熬北,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疙描。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讶隐,死狀恐怖起胰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情巫延,我是刑警寧澤效五,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站炉峰,受9級(jí)特大地震影響畏妖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疼阔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一戒劫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧婆廊,春花似錦迅细、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至宾舅,卻和暖如春统阿,著一層夾襖步出監(jiān)牢的瞬間彩倚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工扶平, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帆离,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓蜻直,卻偏偏與公主長(zhǎng)得像盯质,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子概而,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,721評(píng)論 0 9
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 763評(píng)論 0 1
  • 前言 runtime其實(shí)在我們?nèi)粘i_(kāi)發(fā)過(guò)程中很少使用到囱修,尤其是像我現(xiàn)在比較初級(jí)的程序猿就更用不到了赎瑰。但是去面試很多...
    WolfTin閱讀 625評(píng)論 0 2
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 735評(píng)論 0 2
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,560評(píng)論 33 466