RunTime系統(tǒng)學(xué)習(xí)《一》

一,RunTime介紹

Runtime基本上是用C和匯編寫的寞缝,這個庫使得C語言有了面向?qū)ο蟮哪芰Α?br>

在Runtime中符欠,對象可以用C語言中的結(jié)構(gòu)體表示,而方法可以用C函數(shù)來實現(xiàn)衙荐,另外再加上了一些額外的特性捞挥。這些結(jié)構(gòu)體和函數(shù)被runtime函數(shù)封裝后,讓OC的面向?qū)ο缶幊套優(yōu)榭赡堋?/p>

找出方法的最終執(zhí)行代碼:當程序執(zhí)行[object doSomething]時忧吟,會向消息接收者(object)發(fā)送一條消息(doSomething)砌函,runtime會根據(jù)消息接收者是否能響應(yīng)該消息而做出不同的反應(yīng)。

二 運行時的數(shù)據(jù)類型

Objective-C類是由Class類型來表示的,它實際上是一個指

向objc_class結(jié)構(gòu)體的指針讹俊。

class的實質(zhì)

objc_object

objc_object是表示一個類的實例的結(jié)構(gòu)體

它的定義如下(objc/objc.h):

struct objc_object{

Class isa OBJC_ISA_AVAILABILITY;

};

typedef struct objc_object *id;

可以看出該結(jié)構(gòu)體只有一個字體垦沉,即指向該對象的的isa指針,當我們向該對象發(fā)消息時仍劈,運行時庫會根據(jù)isa指針找到該實例對象所屬的類厕倍,在該類和其父類的類方法列表中找到與消息對應(yīng)的selector指向的方法并運行該方法。

Category

Category是表示一個指向分類的結(jié)構(gòu)體的指針贩疙,其定義如下:

typedef struct objc_category *Category

struct objc_category{

char *category_name? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE; // 分類名

char *class_name? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;? // 分類所屬的類名

struct objc_method_list *instance_methods? OBJC2_UNAVAILABLE;? // 實例方法列表

struct objc_method_list *class_methods? ? ? OBJC2_UNAVAILABLE; // 類方法列表

struct objc_protocol_list *protocols? ? ? ? OBJC2_UNAVAILABLE; // 分類所實現(xiàn)的協(xié)議列表

}

這個結(jié)構(gòu)體主要包含了分類定義的實例方法與類方法绑青,其中instance_methods列表是objc_class中方法列表的一個子集,而class_methods列表是元類方法列表的一個子集屋群。

可發(fā)現(xiàn)闸婴,類別中沒有ivar成員變量指針,也就意味著:類別中不能夠添加實例變量和屬性

RunTime 關(guān)聯(lián)對象

1.設(shè)置關(guān)聯(lián)值

參數(shù)說明:

object:與誰關(guān)聯(lián)芍躏,通常是傳self

key:唯一鍵邪乍,在獲取值時通過該鍵獲取,通常是使用static

const void *來聲明

value:關(guān)聯(lián)所設(shè)置的值

policy:內(nèi)存管理策略对竣,比如使用copy

void objc_setAssociatedObject(id object, const void *key, id value, objc _AssociationPolicy policy)

2.獲取關(guān)聯(lián)值

參數(shù)說明:

object:與誰關(guān)聯(lián)庇楞,通常是傳self,在設(shè)置關(guān)聯(lián)時所指定的與哪個對象關(guān)聯(lián)的那個對象

key:唯一鍵否纬,在設(shè)置關(guān)聯(lián)時所指定的鍵

id objc_getAssociatedObject(id object, const void *key)

3.取消關(guān)聯(lián)

void objc_removeAssociatedObjects(id object)

關(guān)聯(lián)策略

使用場景:

可以在類別中添加屬性

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy){

OBJC_ASSOCIATION_ASSIGN = 0,? ? ? ? ? ? // 表示弱引用關(guān)聯(lián)吕晌,通常是基本數(shù)據(jù)類型

OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,? // 表示強引用關(guān)聯(lián)對象,是線程安全的

OBJC_ASSOCIATION_COPY_NONATOMIC = 3,? ? // 表示關(guān)聯(lián)對象copy临燃,是線程安全的

OBJC_ASSOCIATION_RETAIN = 01401,? ? ? ? // 表示強引用關(guān)聯(lián)對象睛驳,不是線程安全的

OBJC_ASSOCIATION_COPY = 01403? ? ? ? ? ? // 表示關(guān)聯(lián)對象copy,不是線程安全的

};

四膜廊、方法與消息

1乏沸、SEL

SEL又叫選擇器,是表示一個方法的selector的指針爪瓜,其定義如下:

typedef struct objc_selector *SEL蹬跃;

方法的selector用于表示運行時方法的名字。Objective-C在編譯時铆铆,會依據(jù)每一個方法的名字蝶缀、參數(shù)序列,生成一個唯一的整型標識(Int類型的地址)薄货,這個標識就是SEL翁都。

兩個類之間,只要方法名相同菲驴,那么方法的SEL就是一樣的荐吵,每一個方法都對應(yīng)著一個SEL骑冗。所以在Objective-C同一個類(及類的繼承體系)中赊瞬,不能存在2個同名的方法先煎,即使參數(shù)類型不同也不行

通過下面三種方法可以獲取SEL:

a、sel_registerName函數(shù)

b巧涧、Objective-C編譯器提供的@selector()

c薯蝎、NSSelectorFromString()方法

2、IMP

IMP實際上是一個函數(shù)指針谤绳,指向方法實現(xiàn)的地址占锯。

其定義如下:

id (*IMP)(id, SEL,...)

第一個參數(shù):是指向self的指針(如果是實例方法,則是類實例的內(nèi)存地址缩筛;如果是類方法消略,則是指向元類的指針)

第二個參數(shù):是方法選擇器(selector)

接下來的參數(shù):方法的參數(shù)列表。

前面介紹過的SEL就是為了查找方法的最終實現(xiàn)IMP的瞎抛。由于每個方法對應(yīng)唯一的SEL艺演,因此我們可以通過SEL方便快速準確地獲得它所對應(yīng)的IMP,查找過程將在下面討論桐臊。取得IMP后胎撤,我們就獲得了執(zhí)行這個方法代碼的入口點,此時断凶,我們就可以像調(diào)用普通的C語言函數(shù)一樣來使用這個函數(shù)指針了伤提。

3、Method

Method用于表示類定義中的方法认烁,則定義如下:

typedef struct objc_method *Method

struct objc_method{

SEL method_name? ? ? OBJC2_UNAVAILABLE; // 方法名

char *method_types? OBJC2_UNAVAILABLE;

IMP method_imp? ? ? OBJC2_UNAVAILABLE; // 方法實現(xiàn)

}

我們可以看到該結(jié)構(gòu)體中包含一個SEL和IMP肿男,實際上相當于在SEL和IMP之間作了一個映射。有了SEL却嗡,我們便可以找到對應(yīng)的IMP次伶,從而調(diào)用方法的實現(xiàn)代碼。

4方法調(diào)用過程

在OC中消息直到運行時才綁定到方法實現(xiàn)上稽穆,編譯器會將消息表達式轉(zhuǎn)化為消息的函數(shù)調(diào)用冠王,即objc_msgSend。這個函數(shù)將消息接收者和方法名作為其基礎(chǔ)參數(shù)舌镶,如以下所示

objc_msgSend(receiver, selector)柱彻,

如果消息還有其他參數(shù),則表達方式

objc_msgSend(receiver, selector, arg1, arg2,...)

這個消息的函數(shù)內(nèi)部完成了一下事件:

a.首先找到selector指向方法的實現(xiàn)餐胀,因為同一個方法在不同類有不同的實現(xiàn)哟楷,所以必須依賴消息接受類來找到方法實現(xiàn)

b.運行方法實現(xiàn),并將接受消息的對象和參數(shù)傳給他

c.最后將方法實現(xiàn)的返回值作為自己的返回值

消息執(zhí)行順序:當消息發(fā)送給一個對象否灾,現(xiàn)在運行時系統(tǒng)的緩存中找卖擅,如果找到則執(zhí)行方法,如果沒找到,則通過對象的isa指向找到對象的結(jié)構(gòu)體惩阶,在該結(jié)構(gòu)體的方法列表中找挎狸,還沒找到則通過該結(jié)構(gòu)體isa指針找到其父類結(jié)構(gòu)體,在父類結(jié)構(gòu)體方法列表中查找断楷,以此類推一直查找到根源類锨匆。

5、消息轉(zhuǎn)發(fā)

當一個對象能接收一個消息時冬筒,就會走正常的方法調(diào)用流程恐锣。但如果一個對象無法接收指定消息時,又會發(fā)生什么事呢舞痰?默認情況下土榴,如果是以[object message]的方式調(diào)用方法,如果object無法響應(yīng)message消息時响牛,編譯器會報錯鞭衩。但如果是以perform…的形式來調(diào)用,則需要等到運行時才能確定object是否能接收message消息娃善。如果不能论衍,則程序崩潰。

當一個對象無法接收某一消息時聚磺,就會啟動所謂“消息轉(zhuǎn)發(fā)(message forwarding)”機制坯台,通過這一機制,我們可以告訴對象如何處理未知的消息瘫寝。默認情況下蜒蕾,對象接收到未知的消息,會導(dǎo)致程序崩潰焕阿,通過控制臺咪啡,我們可以看到異常信息:

這段異常信息實際上是由NSObject的“doesNotRecognizeSelector”方法拋出的。不過暮屡,我們可以采取一些措施撤摸,讓我們的程序執(zhí)行特定的邏輯,而避免程序的崩潰褒纲。

1>准夷、動態(tài)方法解析

2>、備用接收者

3>莺掠、完整轉(zhuǎn)發(fā)


動態(tài)方法解析

對象在接收到未知的消息時衫嵌,首先會調(diào)用所屬類的類方法

+resolveInstanceMethod:(實例方法)或者

+resolveClassMethod:(類方法)。

在這個方法中彻秆,我們有機會為該未知消息新增一個“處理方法”楔绞,通過運行時class_addMethod函數(shù)動態(tài)添加到類里面就可以了结闸。

這種方案更多的是為了實現(xiàn)@dynamic屬性。

備用接收者

- (id)forwardingTargetForSelector:(SEL)aSelector

如果在上一步無法處理消息酒朵,則Runtime會繼續(xù)調(diào)以下方法:

如果一個對象實現(xiàn)了這個方法桦锄,并返回一個非nil的結(jié)果,則這個對象會作為消息的新接收者耻讽,且消息會被分發(fā)到這個對象。當然這個對象不能是self自身帕棉,否則就是出現(xiàn)無限循環(huán)针肥。當然,如果我們沒有指定相應(yīng)的對象來處理aSelector香伴,則應(yīng)該調(diào)用父類的實現(xiàn)來返回結(jié)果慰枕。

這一步合適于我們只想將消息轉(zhuǎn)發(fā)到另一個能處理該消息的對象上。但這一步無法對消息進行處理即纲,如操作消息的參數(shù)和返回值具帮。

完整消息轉(zhuǎn)發(fā)

如果在上一步還不能處理未知消息,則唯一能做的就是啟用完整的消息轉(zhuǎn)發(fā)機制了低斋。

我們首先要通過,指定方法簽名蜂厅,若返回nil,則表示不處理膊畴。

如下代碼:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

{

if ([NSStringFromSelector(aSelector) isEqualToString:@"testInstanceMethod"]){

return [NSMethodSignature signatureWithObjcTypes:"v@:"];

}

return [super methodSignatureForSelector: aSelector];

}

若返回方法簽名掘猿,則會進入下一步調(diào)用以下方法,對象會創(chuàng)建一個表示消息的NSInvocation對象唇跨,把與尚未處理的消息有關(guān)的全部細節(jié)都封裝在anInvocation中稠通,包括selector,目標(target)和參數(shù)买猖。

我們可以在forwardInvocation方法中選擇將消息轉(zhuǎn)發(fā)給其它對象改橘。我們可以通過anInvocation對象做很多處理,比如修改實現(xiàn)方法玉控,修改響應(yīng)對象等.

如下所示:

- (void)forwardInvovation:(NSInvocation)anInvocation

{

[anInvocation invokeWithTarget:_helper];

[anInvocation setSelector:@selector(run)];

[anInvocation invokeWithTarget:self];

}

方法交換

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末飞主,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子高诺,更是在濱河造成了極大的恐慌既棺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懒叛,死亡現(xiàn)場離奇詭異丸冕,居然都是意外死亡,警方通過查閱死者的電腦和手機薛窥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門胖烛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眼姐,“玉大人,你說我怎么就攤上這事佩番≈谄欤” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵趟畏,是天一觀的道長贡歧。 經(jīng)常有香客問我,道長赋秀,這世上最難降的妖魔是什么利朵? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮猎莲,結(jié)果婚禮上绍弟,老公的妹妹穿的比我還像新娘。我一直安慰自己著洼,他們只是感情好樟遣,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著身笤,像睡著了一般豹悬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上液荸,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天屿衅,我揣著相機與錄音,去河邊找鬼莹弊。 笑死涤久,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的忍弛。 我是一名探鬼主播响迂,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼细疚!你這毒婦竟也來了蔗彤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疯兼,失蹤者是張志新(化名)和其女友劉穎然遏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吧彪,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡待侵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姨裸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秧倾。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡怨酝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出那先,到底是詐尸還是另有隱情农猬,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布售淡,位于F島的核電站斤葱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏揖闸。R本人自食惡果不足惜揍堕,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望楔壤。 院中可真熱鬧鹤啡,春花似錦惯驼、人聲如沸蹲嚣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隙畜。三九已至,卻和暖如春说贝,著一層夾襖步出監(jiān)牢的瞬間议惰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工乡恕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留言询,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓傲宜,卻偏偏與公主長得像运杭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子函卒,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉辆憔,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評論 0 9
  • 前言 runtime其實在我們?nèi)粘i_發(fā)過程中很少使用到,尤其是像我現(xiàn)在比較初級的程序猿就更用不到了报嵌。但是去面試很多...
    WolfTin閱讀 625評論 0 2
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言虱咧,那么這個「動態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,195評論 0 7
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 733評論 0 2
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡介 Runt...
    樂樂的簡書閱讀 2,135評論 0 9