ios開(kāi)發(fā)Runtime詳解part1

Runtime是什么药有?
就像我們開(kāi)發(fā)或者運(yùn)行java程序需要安裝jdk一樣毅戈,使用Objective-C編寫(xiě)的程序也需要在一個(gè)特定的環(huán)境下才能運(yùn)行,這個(gè)環(huán)境就是Objective-C runtime system, 程序運(yùn)行的時(shí)候可以動(dòng)態(tài)載入類(lèi)以及向其他的對(duì)象發(fā)送消息愤惰。
由于現(xiàn)在ios開(kāi)發(fā)已經(jīng)全部需要支持64位了苇经,這里只介紹Objective-C 2.0的runtime, 也被蘋(píng)果稱(chēng)之為 “現(xiàn)代的運(yùn)行時(shí)(the modern runtime)”宦言, 其新的特性為:
當(dāng)在runtime中動(dòng)態(tài)改變一個(gè)類(lèi)中的參數(shù)后扇单,不需要重新編譯這個(gè)類(lèi)的子類(lèi)。
Runtime能做什么奠旺?
鑒于很多文章已經(jīng)對(duì)官方文檔進(jìn)行了翻譯蜘澜,我這里著重總結(jié)一下runtime在實(shí)際場(chǎng)景下的應(yīng)用:

1、Introspection, 獲得對(duì)象中的信息响疚,如Class, Selector(SEL), Method:

現(xiàn)在我們有一個(gè)類(lèi)RuntimeObject.h:


#import <Foundation/Foundation.h>

@interface RuntimeObject : NSObject

@property (nonatomic, strong) NSString *name;

@property (assign) NSInteger age;

- (BOOL)canDrink:(NSInteger)age;

@end

RuntimeObject.m:

#import "RuntimeObject.h"

@implementation RuntimeObject

- (BOOL)canDrink:(NSInteger)age {

    return age >= 18;

}

@end

下面先創(chuàng)建一個(gè)RuntimeObject的實(shí)例:

RuntimeObject *ro = [[RuntimeObject alloc] init];

ro.name = @"Leakey";

ro.age = !28;

獲得類(lèi)的信息:

//    Class class = [ro class];

Class class = object_getClass(ro); //等效[ro class];

//    Class superClass = [ro superclass];

Class superClass = class_getSuperclass(class);//等效[ro superclass];

NSLog(@"super class of %@ is:%@", NSStringFromClass(class), NSStringFromClass(superClass));

// 輸出:super class of RuntimeObject is:NSObject
獲得方法信息:

SEL selector = @selector(canDrink:);

NSLog(@"Selector; %@", NSStringFromSelector(selector));

// 輸出: Selector; shouldHeDrink:

Method method = class_getInstanceMethod(class, @selector(name));

NSLog(@"%d arguments", method_getNumberOfArguments(method));

// 輸出: 2 arguments  

// 方法不管有參數(shù)結(jié)果始終是2鄙信,因?yàn)?objc_msgSend有兩個(gè)參數(shù),一個(gè)是指向?qū)ο蟮闹羔樂拊危粋€(gè)是對(duì)象的selector
判斷是否屬于是否個(gè)類(lèi)的實(shí)現(xiàn)装诡,或者是屬于某個(gè)類(lèi):

NSLog(@"Member of NSObject: %d", [ro isMemberOfClass:[NSObject class]]);

// 輸出: Member of NSObject: 0  因?yàn)閞o不是NSObject的實(shí)例

NSLog(@"Kind of NSObject: %d", [ro isKindOfClass:[NSObject class]]);

// 輸出: Kind of NSObject: 1    RuntimeObject是NSObject的子類(lèi),所以是NSObject
執(zhí)行這個(gè)對(duì)象中的方法:

Objective-C發(fā)送消息的步驟為:

1践盼、向?qū)ο蟀l(fā)送了一個(gè)消息鸦采,每一個(gè)類(lèi)會(huì)有一個(gè)isa指針指向這個(gè)類(lèi)的結(jié)構(gòu)體(structure),在結(jié)構(gòu)體中會(huì)有一個(gè) dispatch table宏侍, 包含這個(gè)類(lèi)中的selector赖淤,如果消息在這個(gè)類(lèi)的dispatch table 中找不到這個(gè)selector,就會(huì)通過(guò)isa指針指向這個(gè)類(lèi)的父類(lèi)谅河,在這個(gè)類(lèi)的super class中找是否含有selector咱旱,直到找到這個(gè)方法再動(dòng)態(tài)綁定這條消息。但是當(dāng)消息發(fā)送到root class還沒(méi)有找到這個(gè)selector的時(shí)候绷耍,就會(huì)報(bào):unrecognized selector sent to instance

// LLVM 6.0后增加了OBJC_OLD_DISPATCH_PROTOTYPES吐限,需要在build setting中將Enable Strict Checking of objc_msgSend Calls設(shè)置為NO才可以使用objc_msgSend(id self, SEL op, ...);

NSString *name = objc_msgSend(ro, @selector(name));

//NSString *name = [ro name];

BOOL canDrink = ((const BOOL (*)(id, SEL, ...))objc_msgSend)(ro, @selector(canDrink:), 24);

canDrink = [ro canDrink:24];

NSLog(@"name is:%@", name);

if (canDrink) {

NSLog(@"%@可以喝酒", name);

} else {

NSLog(@"%@不能喝酒", name);

}

// 輸出: Leakey可以喝酒

使用隱藏的參數(shù):

objc_msgSend方法中有兩個(gè)參數(shù):

1、接收消息的對(duì)象 (id self)

2褂始、方法的selector(SEL op)

_cmd是一個(gè)特別的SEL, 可以在方法里用_cmd獲得這個(gè)方法的信息诸典,通常用來(lái)記錄日志

#define debug 1

- (void)aMethod {

    if (debug==1) {

          NSLog(@"Running %@ '%@'", self.class,NSStringFromSelector(_cmd));

    }

}

// 在AppDelegate中調(diào)用輸出: Running AppDelegate 'aMethod'

獲得方法的地址:

當(dāng)需要很多次調(diào)用方法的時(shí)候,可以通過(guò)這個(gè)方法的地址直接調(diào)用這個(gè)方法崎苗,避免每次去尋找這個(gè)方法的地址狐粱。

NSObject類(lèi)中有一個(gè)methodForSelector:方法,可以返回方法的指針(IMP)舀寓,再通過(guò)這個(gè)指針來(lái)調(diào)用方法可以減少方法調(diào)用所花的時(shí)間。

我們?cè)赗untimeObject中添加一個(gè)方法:

- (void)setNumber: (NSInteger)num {

NSLog(@"%ld", num);

}

調(diào)用1000次此方法可以用以下寫(xiě)法:

void (*setter)(id, SEL, NSInteger);

int i;

// ro是之前創(chuàng)建的RuntimeObject對(duì)象

setter = (void (*)(id, SEL, NSInteger))[ro

methodForSelector:@selector(setNumber:)];

for ( i = 0 ; i < 1000 ; i++ )

setter(ro, @selector(setNumber:), i);

這里是一個(gè)對(duì)象調(diào)用多次方法肌蜻,當(dāng)然多個(gè)實(shí)體調(diào)用同一個(gè)方法只需將最后一行setter中的ro改成對(duì)應(yīng)的 targetList[i]即可互墓,要注意的是前面定義的void (*setter)(id, SEL, NSInteger);里的參數(shù)必須與需要調(diào)用的方法的參數(shù)一致,其中id,SEL是objc_msgSend的前兩個(gè)參數(shù)蒋搜, 后面的是方法的參數(shù)篡撵。

此文列舉了用runtime獲取class、selector以及method的信息豆挽,以及一些使用場(chǎng)景育谬,我也會(huì)不斷完善runtime在實(shí)際項(xiàng)目中的用法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帮哈,一起剝皮案震驚了整個(gè)濱河市膛檀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌娘侍,老刑警劉巖宿刮,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異私蕾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)胡桃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)踩叭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人翠胰,你說(shuō)我怎么就攤上這事容贝。” “怎么了之景?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵斤富,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我锻狗,道長(zhǎng)满力,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任轻纪,我火速辦了婚禮油额,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刻帚。我一直安慰自己潦嘶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布崇众。 她就那樣靜靜地躺著掂僵,像睡著了一般航厚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锰蓬,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天幔睬,我揣著相機(jī)與錄音,去河邊找鬼互妓。 笑死溪窒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冯勉。 我是一名探鬼主播澈蚌,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼灼狰!你這毒婦竟也來(lái)了宛瞄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤交胚,失蹤者是張志新(化名)和其女友劉穎份汗,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蝴簇,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杯活,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了熬词。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旁钧。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖互拾,靈堂內(nèi)的尸體忽然破棺而出歪今,到底是詐尸還是另有隱情,我是刑警寧澤颜矿,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布寄猩,位于F島的核電站,受9級(jí)特大地震影響骑疆,放射性物質(zhì)發(fā)生泄漏田篇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一封断、第九天 我趴在偏房一處隱蔽的房頂上張望斯辰。 院中可真熱鬧,春花似錦坡疼、人聲如沸彬呻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)闸氮。三九已至剪况,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒲跨,已是汗流浹背译断。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留或悲,地道東北人孙咪。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像巡语,于是被迫代替她去往敵國(guó)和親翎蹈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉男公,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評(píng)論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,554評(píng)論 33 466
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡(jiǎn)介 Runt...
    樂(lè)樂(lè)的簡(jiǎn)書(shū)閱讀 2,135評(píng)論 0 9
  • objc_getAssociatedObject返回與給定鍵的特定對(duì)象關(guān)聯(lián)的值荤堪。ID objc_getAssoci...
    有一種再見(jiàn)叫青春閱讀 1,582評(píng)論 0 7
  • 真的覺(jué)得今夜好長(zhǎng)啊,前半晚在聽(tīng)課枢赔,收獲豐富澄阳,期待落地~ 聽(tīng)完課后趕快來(lái)整理飯店這幾天的賬務(wù),最不擅長(zhǎng)搞數(shù)字的人踏拜,在...
    happyMia閱讀 157評(píng)論 0 0