Runtime

來(lái)源:iOS 模塊注解—「Runtime面試刻坊、工作」看我就 ?? 了 ^_^. - 簡(jiǎn)書(shū)

runtime(簡(jiǎn)稱(chēng)運(yùn)行時(shí))枷恕,是一套 純C(C和匯編寫(xiě)的) 的API。 ?是運(yùn)行時(shí)機(jī)制谭胚,也就是在運(yùn)行時(shí)候的一些機(jī)制徐块,其中最主要的是消息機(jī)制消息機(jī)制原理:對(duì)象根據(jù)方法編號(hào)SEL去映射表查找對(duì)應(yīng)的方法實(shí)現(xiàn)灾而。

每一個(gè) OC 的方法胡控,底層必然有一個(gè)與之對(duì)應(yīng)的?runtime?方法。任何方法調(diào)用本質(zhì):就是發(fā)送一個(gè)消息(用?runtime發(fā)送消息旁趟,OC 底層實(shí)現(xiàn)通過(guò)?runtime?實(shí)現(xiàn))昼激。

對(duì)于 C 語(yǔ)言,函數(shù)的調(diào)用在編譯的時(shí)候會(huì)決定調(diào)用哪個(gè)函數(shù)锡搜。

OC在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)橙困,只有在真正運(yùn)行的時(shí)候才會(huì)根據(jù)函數(shù)的名稱(chēng)找到對(duì)應(yīng)的函數(shù)來(lái)調(diào)用,在編譯階段耕餐,OC 可以?調(diào)用任何函數(shù)凡傅,即使這個(gè)函數(shù)并未實(shí)現(xiàn),只要聲明過(guò)就不會(huì)報(bào)錯(cuò)蛾方,只有當(dāng)運(yùn)行的時(shí)候才會(huì)報(bào)錯(cuò)像捶,這是因?yàn)镺C是運(yùn)行時(shí)動(dòng)態(tài)調(diào)用的。而 C 語(yǔ)言?調(diào)用未實(shí)現(xiàn)的函數(shù)?就會(huì)報(bào)錯(cuò)桩砰。


runtime 方法調(diào)用流程「消息機(jī)制」

面試:消息機(jī)制方法調(diào)用流程

怎么去調(diào)用eat方法拓春,對(duì)象方法:(保存到類(lèi)對(duì)象的方法列表) ,類(lèi)方法:(保存到元類(lèi)(Meta Class)中方法列表)亚隅。

1.OC 在向一個(gè)對(duì)象發(fā)送消息時(shí)硼莽,runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象對(duì)應(yīng)的類(lèi)或其父類(lèi)中查找方法。煮纵。

2.注冊(cè)方法編號(hào)(這里用方法編號(hào)的好處懂鸵,可以快速查找)。

3.根據(jù)方法編號(hào)去查找對(duì)應(yīng)方法行疏。

4.找到只是最終函數(shù)實(shí)現(xiàn)地址匆光,根據(jù)地址去方法區(qū)調(diào)用對(duì)應(yīng)函數(shù)。

補(bǔ)充:一個(gè)objc對(duì)象的isa的指針指向什么酿联?有什么作用终息?

每一個(gè)對(duì)象內(nèi)部都有一個(gè)isa指針,這個(gè)指針是指向它的真實(shí)類(lèi)型贞让,根據(jù)這個(gè)指針就能知道將來(lái)調(diào)用哪個(gè)類(lèi)的方法周崭。

runtime 常見(jiàn)作用

1.交換方法/添加方法

// 1.獲取 imageNamed方法地址

// class_getClassMethod(獲取某個(gè)類(lèi)的方法)

Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));

// 2.獲取 ln_imageNamed方法地址

Method ln_imageNamedMethod = class_getClassMethod(self, @selector(ln_imageNamed:));

// 3.交換方法地址,相當(dāng)于交換實(shí)現(xiàn)方式;「method_exchangeImplementations 交換兩個(gè)方法的實(shí)現(xiàn)」

method_exchangeImplementations(imageNamedMethod, ln_imageNamedMethod);?

2.為分類(lèi)添加屬性

- (void)setName:(NSString *)name {

// objc_setAssociatedObject(將某個(gè)值跟某個(gè)對(duì)象關(guān)聯(lián)起來(lái)喳张,將某個(gè)值存儲(chǔ)到某個(gè)對(duì)象中)

// object:給哪個(gè)對(duì)象添加屬性 // key:屬性名稱(chēng) // value:屬性值 // policy:保存策略 objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}

- (NSString *)name {

return objc_getAssociatedObject(self, @"name");

}?

3.字典轉(zhuǎn)模型

// Runtime:根據(jù)模型中屬性,去字典中取出對(duì)應(yīng)的value給模型屬性賦值// 思路:遍歷模型中所有屬性->使用運(yùn)行時(shí)

+ (instancetype)modelWithDict:(NSDictionary *)dict{

// 1.創(chuàng)建對(duì)應(yīng)的對(duì)象

id objc = [[self alloc] init];

// 2.利用runtime給對(duì)象中的屬性賦值 /** class_copyIvarList: 獲取類(lèi)中的所有成員變量

Ivar:成員變量 第一個(gè)參數(shù):表示獲取哪個(gè)類(lèi)中的成員變量

第二個(gè)參數(shù):表示這個(gè)類(lèi)有多少成員變量续镇,傳入一個(gè)Int變量地址,會(huì)自動(dòng)給這個(gè)變量賦值 返回值Ivar *:指的是一個(gè)ivar數(shù)組销部,會(huì)把所有成員屬性放在一個(gè)數(shù)組中摸航,通過(guò)返回的數(shù)組就能全部獲取到。 count: 成員變量個(gè)數(shù) */ unsigned int count = 0; // 獲取類(lèi)中的所有成員變量

Ivar *ivarList = class_copyIvarList(self, &count);

// 遍歷所有成員變量

for (int i = 0; i < count; i++) {

// 根據(jù)角標(biāo)柴墩,從數(shù)組取出對(duì)應(yīng)的成員變量

Ivar ivar = ivarList[i];

// 獲取成員變量名字

NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];

// 處理成員變量名->字典中的key(去掉 _ ,從第一個(gè)角標(biāo)開(kāi)始截取)

NSString *key = [ivarName substringFromIndex:1];

// 根據(jù)成員屬性名去字典中查找對(duì)應(yīng)的

value id value = dict[key];

// 【如果模型屬性數(shù)量大于字典鍵值對(duì)數(shù)理忙厌,模型屬性會(huì)被賦值為nil】

// 而報(bào)錯(cuò) (could not set nil as the value for the key age.)

if (value) {

// 給模型中屬性賦值

[objc setValue:value forKey:key];

} }

return objc;

}?


原因:Ivar:成員變量,以下劃線開(kāi)頭,Property 屬性

獲取類(lèi)里面屬性?class_copyPropertyList

獲取類(lèi)中的所有成員變量?class_copyIvarList

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

【iOS】消息轉(zhuǎn)發(fā)機(jī)制 - 簡(jiǎn)書(shū)


應(yīng)用場(chǎng)景:如果一個(gè)類(lèi)方法非常多江咳,加載類(lèi)到內(nèi)存的時(shí)候也比較耗費(fèi)資源逢净,需要給每個(gè)方法生成映射表,可以使用動(dòng)態(tài)給某個(gè)類(lèi)歼指,添加方法解決爹土。

注解:OC 中我們很習(xí)慣的會(huì)用懶加載,當(dāng)用到的時(shí)候才去加載它踩身,但是實(shí)際上只要一個(gè)類(lèi)實(shí)現(xiàn)了某個(gè)方法胀茵,就會(huì)被加載進(jìn)內(nèi)存。當(dāng)我們不想加載這么多方法的時(shí)候挟阻,就會(huì)使用到 runtime 動(dòng)態(tài)的添加方法琼娘。

需求:runtime 動(dòng)態(tài)添加方法處理調(diào)用一個(gè)未實(shí)現(xiàn)的方法 和 去除報(bào)錯(cuò)峭弟。

+ (BOOL)resolveInstanceMethod:(SEL)sel

- (id)forwardingTargetForSelector:(SEL)aSelector

經(jīng)歷了前兩步,還是無(wú)法處理消息脱拼,那么就會(huì)做最后的嘗試瞒瘸,先調(diào)用methodSignatureForSelector:獲取方法簽名,用簽名生成invocation然后再調(diào)用forwardInvocation:進(jìn)行處理熄浓,這一步的處理可以直接轉(zhuǎn)發(fā)給其它對(duì)象情臭,即和第二步的效果等效,但是很少有人這么干赌蔑,因?yàn)橄⑻幚碓娇亢蟾┰冢捅硎咎幚硐⒌某杀驹酱螅阅艿拈_(kāi)銷(xiāo)就越大娃惯。所以跷乐,在這種方式下,會(huì)改變消息內(nèi)容趾浅,比如增加參數(shù)劈猿,改變選擇子等等。

消息轉(zhuǎn)發(fā)給其他對(duì)象時(shí)潮孽,可以穿多個(gè)參數(shù)

NSInvocation詳解 - 簡(jiǎn)書(shū)



問(wèn)題: objc在向一個(gè)對(duì)象發(fā)送消息時(shí)揪荣,發(fā)生了什么?

解答: 根據(jù)對(duì)象的 isa 指針找到類(lèi)對(duì)象 id往史,在查詢(xún)類(lèi)對(duì)象里面的 methodLists 方法函數(shù)列表仗颈,如果沒(méi)有在好到,在沿著 superClass ,尋找父類(lèi)椎例,再在父類(lèi) methodLists 方法列表里面查詢(xún)挨决,最終找到 SEL ,根據(jù) id 和 SEL 確認(rèn) IMP(指針函數(shù)),在發(fā)送消息;

03

問(wèn)題: 什么時(shí)候會(huì)報(bào)unrecognized selector錯(cuò)誤订歪?iOS有哪些機(jī)制來(lái)避免走到這一步脖祈?

解答: 當(dāng)發(fā)送消息的時(shí)候,我們會(huì)根據(jù)類(lèi)里面的 methodLists 列表去查詢(xún)我們要?jiǎng)佑玫腟EL刷晋,當(dāng)查詢(xún)不到的時(shí)候盖高,我們會(huì)一直沿著父類(lèi)查詢(xún),當(dāng)最終查詢(xún)不到的時(shí)候我們會(huì)報(bào) unrecognized selector 錯(cuò)誤眼虱,當(dāng)系統(tǒng)查詢(xún)不到方法的時(shí)候喻奥,會(huì)調(diào)用 +(BOOL)resolveInstanceMethod:(SEL)sel 動(dòng)態(tài)解釋的方法來(lái)給我一次機(jī)會(huì)來(lái)添加,調(diào)用不到的方法捏悬∽膊希或者我們可以再次使用 -(id)forwardingTargetForSelector:(SEL)aSelector 重定向的方法來(lái)告訴系統(tǒng),該調(diào)用什么方法过牙,一來(lái)保證不會(huì)崩潰甥厦。

經(jīng)歷了前兩步纺铭,還是無(wú)法處理消息,那么就會(huì)做最后的嘗試刀疙,先調(diào)用methodSignatureForSelector:獲取方法簽名彤蔽,然后再調(diào)用forwardInvocation:進(jìn)行處理,這一步的處理可以直接轉(zhuǎn)發(fā)給其它對(duì)象庙洼,即和第二步的效果等效,但是很少有人這么干镊辕,因?yàn)橄⑻幚碓娇亢笥凸唬捅硎咎幚硐⒌某杀驹酱螅阅艿拈_(kāi)銷(xiāo)就越大征懈。所以石咬,在這種方式下,會(huì)改變消息內(nèi)容卖哎,比如增加參數(shù)鬼悠,改變選擇子等等。

?鏈接:http://www.reibang.com/p/5dd7703ce2fc

04

問(wèn)題: 能否向編譯后得到的類(lèi)中增加實(shí)例變量亏娜?能否向運(yùn)行時(shí)創(chuàng)建的類(lèi)中添加實(shí)例變量焕窝?為什么?

解答: 1维贺、不能向編譯后得到的類(lèi)增加實(shí)例變量 2它掂、能向運(yùn)行時(shí)創(chuàng)建的類(lèi)中添加實(shí)例變量∷萜【解釋】:1. 編譯后的類(lèi)已經(jīng)注冊(cè)在 runtime 中,類(lèi)結(jié)構(gòu)體中的 objc_ivar_list 實(shí)例變量的鏈表和 instance_size 實(shí)例變量的內(nèi)存大小已經(jīng)確定虐秋,runtime會(huì)調(diào)用 class_setvarlayout 或 class_setWeaklvarLayout 來(lái)處理strong weak 引用.所以不能向存在的類(lèi)中添加實(shí)例變量。2. 運(yùn)行時(shí)創(chuàng)建的類(lèi)是可以添加實(shí)例變量垃沦,調(diào)用class_addIvar函數(shù). 但是的在調(diào)用 objc_allocateClassPair 之后客给,objc_registerClassPair 之前,原因同上.

05

問(wèn)題: runtime如何實(shí)現(xiàn)weak變量的自動(dòng)置nil?

解答: runtime 對(duì)注冊(cè)的類(lèi)肢簿, 會(huì)進(jìn)行布局靶剑,對(duì)于 weak 對(duì)象會(huì)放入一個(gè) hash 表中。 用 weak 指向的對(duì)象內(nèi)存地址作為 key池充,當(dāng)此對(duì)象的引用計(jì)數(shù)為0的時(shí)候會(huì) dealloc抬虽,假如 weak 指向的對(duì)象內(nèi)存地址是a,那么就會(huì)以a為鍵纵菌, 在這個(gè) weak 表中搜索阐污,找到所有以a為鍵的 weak 對(duì)象,從而設(shè)置為 nil咱圆。

06

問(wèn)題: 給類(lèi)添加一個(gè)屬性后笛辟,在類(lèi)結(jié)構(gòu)體里哪些元素會(huì)發(fā)生變化功氨?

解答: instance_size :實(shí)例的內(nèi)存大小手幢;objc_ivar_list *ivars:屬性列表


一捷凄、oc語(yǔ)言的特性

OC做為一門(mén)面向?qū)ο笳Z(yǔ)言,具有面向?qū)ο蟮恼Z(yǔ)言特性围来,如封裝跺涤、繼承、多態(tài)监透。他具有靜態(tài)語(yǔ)言的特性(如C++)桶错,又有動(dòng)態(tài)語(yǔ)言的效率(動(dòng)態(tài)綁定、動(dòng)態(tài)加載等)胀蛮。

OC的動(dòng)態(tài)特性表現(xiàn)為了三個(gè)方面:動(dòng)態(tài)類(lèi)型院刁、動(dòng)態(tài)綁定、動(dòng)態(tài)加載粪狼。之所以叫做動(dòng)態(tài)退腥,是因?yàn)楸仨毜竭\(yùn)行時(shí)(run time)才會(huì)做一些事情。

(1)動(dòng)態(tài)類(lèi)型

動(dòng)態(tài)類(lèi)型再榄,說(shuō)簡(jiǎn)單點(diǎn)就是id類(lèi)型狡刘。動(dòng)態(tài)類(lèi)型是跟靜態(tài)類(lèi)型相對(duì)的。像內(nèi)置的明確的基本類(lèi)型都屬于靜態(tài)類(lèi)型(int困鸥、NSString等)颓帝。靜態(tài)類(lèi)型在編譯的時(shí)候就能被識(shí)別出來(lái)。所以窝革,若程序發(fā)生了類(lèi)型不對(duì)應(yīng)购城,編譯器就會(huì)發(fā)出警告。而動(dòng)態(tài)類(lèi)型就編譯器編譯的時(shí)候是不能被識(shí)別的虐译,要等到運(yùn)行時(shí)(run time)瘪板,即程序運(yùn)行的時(shí)候才會(huì)根據(jù)語(yǔ)境來(lái)識(shí)別。所以這里面就有兩個(gè)概念要分清:編譯時(shí)跟運(yùn)行時(shí)漆诽∥昱剩基本的動(dòng)態(tài)特性在常規(guī)的Cocoa開(kāi)發(fā)中非常常用,特別是動(dòng)態(tài)類(lèi)型和動(dòng)態(tài)綁定厢拭。由于Cocoa程序大量地使用Protocol-Delegate的 設(shè)計(jì)模式兰英,因此絕大部分的delegate指針類(lèi)型必須是id,以滿足運(yùn)行時(shí)delegate的動(dòng)態(tài)替

(2)動(dòng)態(tài)綁定

動(dòng)態(tài)綁定(dynamic binding)供鸠,讓代碼在運(yùn)行時(shí)判斷需要調(diào)用什么方法畦贸,而不是在編譯時(shí)。與其他面向?qū)ο笳Z(yǔ)言一樣,方法調(diào)用和代碼并沒(méi)有在編譯時(shí)連接在一起薄坏,而是在消息發(fā)送時(shí)才進(jìn)行連接趋厉。運(yùn)行時(shí)決定調(diào)用哪個(gè)方法。

(3)動(dòng)態(tài)加載

根據(jù)需求加載所需要的資源胶坠,這點(diǎn)很容易理解君账,對(duì)于iOS開(kāi)發(fā)來(lái)說(shuō),基本就是根據(jù)不同的機(jī)型做適配沈善。最經(jīng)典的例子就是在Retina設(shè)備上加載@2x 的圖片乡数,而在老一些的普通屏設(shè)備上加載原圖。隨著Retina iPad的推出闻牡,和之后可能的Retina Mac的出現(xiàn)净赴,這個(gè)特性相信會(huì)被越來(lái)越多地使用。

oc 語(yǔ)言的優(yōu)點(diǎn):類(lèi)目澈侠、動(dòng)態(tài)識(shí)別、支持c語(yǔ)言埋酬、oc與c++可以混編

缺點(diǎn):不支持命名空間哨啃、不支持運(yùn)算符重載、不支持多重繼承

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末写妥,一起剝皮案震驚了整個(gè)濱河市拳球,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌珍特,老刑警劉巖祝峻,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扎筒,居然都是意外死亡莱找,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)嗜桌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奥溺,“玉大人,你說(shuō)我怎么就攤上這事骨宠「《ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵层亿,是天一觀的道長(zhǎng)桦卒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)匿又,這世上最難降的妖魔是什么方灾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮碌更,結(jié)果婚禮上迎吵,老公的妹妹穿的比我還像新娘躲撰。我一直安慰自己,他們只是感情好击费,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布拢蛋。 她就那樣靜靜地躺著,像睡著了一般蔫巩。 火紅的嫁衣襯著肌膚如雪谆棱。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天圆仔,我揣著相機(jī)與錄音垃瞧,去河邊找鬼。 笑死坪郭,一個(gè)胖子當(dāng)著我的面吹牛个从,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播歪沃,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼嗦锐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了沪曙?” 一聲冷哼從身側(cè)響起奕污,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎液走,沒(méi)想到半個(gè)月后碳默,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缘眶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年嘱根,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巷懈。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡儿子,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出砸喻,到底是詐尸還是另有隱情柔逼,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布割岛,位于F島的核電站譬涡,受9級(jí)特大地震影響裳凸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一壤追、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸瞬哼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坐慰。三九已至,卻和暖如春用僧,著一層夾襖步出監(jiān)牢的瞬間结胀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工责循, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留糟港,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓院仿,卻偏偏與公主長(zhǎng)得像秸抚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歹垫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

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