Runtime梳理(一)

挖就挖底層.png

看這篇文章關(guān)于Runtime的話,主要是有OC基礎(chǔ)的同學(xué),共勉吧!
本文我自己的目的是:“ 弄清楚什么是 Runtime薇组,并對Runtime有一定的基本了解,可以在開發(fā)過程中把Runtime運(yùn)用自如.”

什么是 Runtime

  • 簡而言之坐儿,Objective-C Runtime是一個將C語言轉(zhuǎn)化為面向?qū)ο笳Z言的擴(kuò)展.
  • C++是基于靜態(tài)類型,Objective-C是基于動態(tài)運(yùn)行時類型.
  • 通過Runtime把程序轉(zhuǎn)為可令機(jī)器讀懂的機(jī)器語言,Runtime是Objective不可缺少的重要一部分.

本章分成兩個部分進(jìn)行學(xué)習(xí):1. OC元素的認(rèn)知 2. OC消息傳遞

第一部分:OC元素的認(rèn)知:

子類 類 父類 元類 根類 其中指針指向和集成的關(guān)系自己梳理律胀,這里不多說,下面我們講Runtime的構(gòu)成貌矿,最快捷的了解方法就是進(jìn)去ios 9.2/usr/include/objc/objc或runtime隨便看看炭菌。總結(jié)如下:

主要有七個構(gòu)件:1.id和Class 2. SEL 3. Method 4. IMP 5. Ivar 6.Cache 7. Category

一. id和Class

objc_isa_availability
typedef struct
object_class *Class逛漫、黑低、類
objc_object Class object_class isa OBJC_ISA_AVAILABILITY、酌毡、isa指針
objc_object *id

  1. Class是一個指向objc_class結(jié)構(gòu)體的指針克握,
  2. id是一個指向objc_object結(jié)構(gòu)體的指針,
  3. isa是一個指向objc_class`結(jié)構(gòu)體的指針枷踏。
  4. id就是我們所說的對象菩暗,Class就是我們所說的類。

Class super_class OBJC2_UNAVAILABLE旭蠕、停团、父類
const char *name OBJC2_UNAVAILABLE、掏熬、類名

long version OBJC2_UNAVAILABLE佑稠、、類的版本信息孽江,默認(rèn)為0讶坯,可以通過runtime函數(shù)class_setVersion或者class_getVersion進(jìn)行修改、讀取

long info OBJC2_UNAVAILABLE岗屏、辆琅、類信息,供運(yùn)行時期使用的一些位標(biāo)識这刷,如CLS_CLASS (0x1L)表示該類為普通class婉烟,其中包含實(shí)例方法和變量;CLS_META (0x2L)表示該類為metaclass,其中包含類方法;

long instance_size OBJC2_UNAVAILABLE暇屋、似袁、該類的實(shí)例變量大小(包括從父類繼承下來的實(shí)例變量)

objec_ivar_list *ivars OBJC2_UNAVAILABLE咐刨、昙衅、該類的成員變量地址列表

objc_method_list **methodLists OBJC2_UNAVAILABLE、定鸟、方法地址列表而涉,與info的一些標(biāo)志位有關(guān),如CLS_CLASS (0x1L)联予,則存儲實(shí)例方法啼县,如CLS_META (0x2L),則存儲類方法;

objc_cache_list *cache OBJC2_UNAVAILABLE沸久、季眷、緩存最近使用的方法地址,用于提升效率卷胯;

objc_protocol_list *protocols OBJC2_UNAVAILABLE子刮、、存儲該類聲明遵守的協(xié)議的列表

二. SEL

  1. SELselector在Objective-C中的表示類型窑睁。
  1. selector可以理解為區(qū)別方法的ID话告。
    objc_selector *SEL
    objc_selector char * name OBJC2_UNAVLABLE名稱
    char *type

nametypes都是char類型。

三. IMP

id (* IMP)(id,SEL,...);
IMP是“implementation”的縮寫卵慰,它是由編譯器生成的一個函數(shù)指針沙郭。
當(dāng)你發(fā)起一個消息后(下文介紹),這個函數(shù)指針決定了最終執(zhí)行哪段代碼

四. Method

Method代表類中的某個方法的類型

objc_method *Method
objc_method SEL method_name OBJC2_UNAVAILABLE裳朋、病线、方法名
obcj_method char *method_types OBJC2_UNAVAILABLE、鲤嫡、方法類型
IMP method_imp OBJC2_UNAVAILABLE送挑、、方法實(shí)現(xiàn)

  1. 方法名method_name類型為SEL暖眼,上文提到過惕耕。
  2. 方法類型method_types是一個char指針,存儲著方法的參數(shù)類型和返回值類型诫肠。
  3. 方法實(shí)現(xiàn)method_imp的類型為IMP司澎,上文提到過欺缘。

五. Ivar

Ivar代表類中實(shí)例變量的類型
objc_ivar *Ivar
objc_ivar char *ivar_name OBJC2_UNAVAILABLE、挤安、變量名
objc_ivar char *ivar_type OBJC2_UNAVAILABLE谚殊、、變量類型
objc_ivar int ivar_offset OBJC2_UNAVAILABLE蛤铜、嫩絮、基地址偏移字節(jié)
objc_ivar int space OBJC2_UNAVAILABLE、围肥、占用空間
objc_propery_t
objc_property_t是屬性
objc_property *objc_property_t;

  1. objc_property是內(nèi)置的類型剿干,與之關(guān)聯(lián)的還有一個objc_property_attribute_t,它是屬性的attribute穆刻,
  2. 也就是其實(shí)是對屬性的詳細(xì)描述置尔,包括屬性名稱、屬性編碼類型蛹批、原子類型/非原子類型等

const char*name撰洗、、名稱
const char*value腐芍、差导、值(通常為空的)
------ objc_property_attribute_t

六. Cache

objc_cache *Cache
objc_cache unsigned int mask OBJC2_UNAVAILABLE、猪勇、
unsigned int occupiedOBJC2_UNAVAILABLE设褐、、
Method buckets[1]OBJC2_UNAVAILABLE泣刹、助析、

  1. mask:指定分配cache buckets的總數(shù)。
  2. 在方法查找中椅您,Runtime使用這個字段確定數(shù)組的索引位置外冀。
  3. occupied:實(shí)際占用cache buckets的總數(shù)。
  4. buckets:指定Method數(shù)據(jù)結(jié)構(gòu)指針的數(shù)組掀泳。
  5. 這個數(shù)組可能包含不超過mask+1個元素雪隧。
  6. 需要注意的是,指針可能是NULL员舵,
  7. 表示這個緩存bucket沒有被占用脑沿,另外被占用的bucket可能是不連續(xù)的。
  8. 這個數(shù)組可能會隨著時間而增長马僻。
  9. objc_msgSend(下文講解)每調(diào)用一次方法后庄拇,就會把該方法緩存到cache列表中
  10. 下次的時候,就直接優(yōu)先從cache列表中尋找韭邓,如果cache沒有措近,才從methodLists中查找方法溶弟。

七. Category

就是我們平時所說的類別了,很熟悉吧熄诡。它可以動態(tài)的為已存在的類添加新的方法
objc_catagory *Category
char *category OBJC2_UNAVAILABLE可很、诗力、類別名稱
char *class_name OBJC2_UNAVAILABLE凰浮、、類名
objc_method_list *instance_methods OBJC2_UNAVAILABLE苇本、袜茧、實(shí)例方法列表
objc_method_list *class_methods OBJC2_UNAVAILABLE、瓣窄、類方法列表
objc_method_list *protocols OBJC2_UNAVAILABLE笛厦、、協(xié)議列表

這小補(bǔ)充一點(diǎn):objc_AssociationPolicy關(guān)聯(lián)策略俺夕,有以下幾種策略:

enum { 
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, OBJC_ASSOCIATION_COPY_NONATOMIC = 3, 
OBJC_ASSOCIATION_RETAIN = 01401, 
OBJC_ASSOCIATION_COPY = 01403 
};

// 后面用得到裳凸。。劝贸。姨谷。

第二部分:OC消息傳遞:

一. 基本消息傳遞

1.在面向?qū)ο缶幊讨校瑢ο笳{(diào)用方法叫做發(fā)送消息映九。
2.在編譯時梦湘,程序的源代碼就會從對象發(fā)送消息轉(zhuǎn)換成Runtime的objc_msgSend函數(shù)調(diào)用。

例如某實(shí)例變量receiver實(shí)現(xiàn)某一個方法oneMethod
[receiver oneMethod] Runtime會將其轉(zhuǎn)成類似這樣的代碼:objc_msgSend(receiver, selector);

  1. Runtime會根據(jù)類型自動轉(zhuǎn)換成下列某一個函數(shù):
  1. objc_msgSend:普通的消息都會通過該函數(shù)發(fā)
  2. objc_msgSend_stret:消息中有數(shù)據(jù)結(jié)構(gòu)作為返回值(不是簡單值)時件甥,通過此函數(shù)發(fā)送和接收返回值
  3. objc_msgSendSuper:objc_msgSend類似捌议,這里把消息發(fā)送給父類的實(shí)例
    5.objc_msgSendSuper_stret:objc_msgSend_stret類似,這里把消息發(fā)送給父類的實(shí)例并接收返回值

二. objc_msgSend函數(shù)的調(diào)用過程:

  • 第一步:檢測這個selector是不是要忽略的引有。
    第二步:檢測這個target是不是nil對象瓣颅。nil對象發(fā)送任何一個消息都會被忽略掉。
    第三步:

    1. 調(diào)用實(shí)例方法時譬正,它會首先在自身isa指針指向的類(class)methodLists中查找該方法宫补,
      如果找不到則會通過class的super_class指針找到父類的類對象結(jié)構(gòu)體,
      然后從methodLists中查找該方法导帝,
      如果仍然找不到守谓,則繼續(xù)通過super_class向上一級父類結(jié)構(gòu)體中查找,
      直至根class您单;
    2. 當(dāng)我們調(diào)用某個某個類方法時斋荞,它會首先通過自己的isa指針找到metaclass
      并從其中methodLists中查找該類方法虐秦,
      如果找不到則會通過metaclasssuper_class指針找到父類的metaclass對象結(jié)構(gòu)體平酿,
      然后從methodLists中查找該方法凤优,
      如果仍然找不到,則繼續(xù)通過super_class向上一級父類結(jié)構(gòu)體中查找蜈彼,
      直至根metaclass筑辨;

第四步:前三部都找不到就會進(jìn)入動態(tài)方法解析(看下文

三. 消息動態(tài)解析

演示:

  • 第一步:
    通過resolveInstanceMethod:方法決定是否動態(tài)添加方法。
    如果返回Yes則通過class_addMethod動態(tài)添加方法幸逆,消息得到處理棍辕,結(jié)束;
    如果返回No还绘,則進(jìn)入下一步楚昭;

  • 第二步:
    這步會進(jìn)入forwardingTargetForSelector:方法,
    用于指定備選對象響應(yīng)這個selector拍顷,不能指定為self抚太。
    如果返回某個對象則會調(diào)用對象的方法,結(jié)束昔案。
    如果返回nil尿贫,則進(jìn)入第三部;

  • 第三步:
    這步我們要通過methodSignatureForSelector:方法簽名踏揣,
    如果返回nil庆亡,則消息無法處理。
    如果返回methodSignature呼伸,則進(jìn)入下一步身冀;

  • 第四步:
    這步調(diào)用forwardInvocation:方法,
    我們可以通過anInvocation對象做很多處理括享,
    比如修改實(shí)現(xiàn)方法搂根,修改響應(yīng)對象等,如果方法調(diào)用成功铃辖,則結(jié)束剩愧。
    如果失敗,則進(jìn)入doesNotRecognizeSelector方法娇斩,
    若我們沒有實(shí)現(xiàn)這個方法仁卷,那么就會crash

案例:

import <Foundation/Foundation.h>

if TARGET_IPHONE_SIMULATOR

import <objc/objc-runtime.h>

else

import <objc/runtime.h>

import <objc/message.h>

endif


 *  自定義函數(shù)
> ````
void sayFunction(id self, SEL _cmd, id some)
{
    NSLog(@"%@歲的%@說:%@",
          object_getIvar(self, class_getInstanceVariable([self class], "_age")),[self valueForKey:@"name"], some);
}

int main(int argc, const char * argv[]) {
// 添加了一個類
Class People = objc_allocateClassPair([NSObject class], "Person", 0);
// 給這個類添加了兩屬性 name age
class_addIvar(People, "_name", sizeof(NSString*), log2(sizeof(NSString *)), @encode(NSString ));
class_addIvar(People, "_age", sizeof(int), sizeof(int), @encode(int));
// 生成一個方法
SEL s = sel_registerName("say:");
class_addMethod(People, s, (IMP)sayFunction, "good");
// 注冊這個類
objc_registerClassPair(People);
// 對象
id peopleInstance = [[People alloc] init];
// 屬性值
[peopleInstance setValue:@"小萌" forKey:@"name"];
Ivar ageIvar = class_getInstanceVariable(People, "_age");
// 動態(tài)賦值
object_setIvar(peopleInstance, ageIvar, @18);
// 調(diào)用方法
((void (
)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好");
// 銷毀對象
peopleInstance = nil;
objc_disposeClassPair(People);
return 0;
}


打印結(jié)果如下:
> 2016-04-08 18:52:15.009 RuntimeLine[4710:394843] 18歲的小明說:大家好 
Program ended with exit code: 0

默認(rèn)會出現(xiàn)以下錯誤:
“`objc_msgSend()`報錯Too many arguments to function call ,expected 0,have3”
直接通過`objc_msgSend(self, setter, value)`是報錯,說參數(shù)過多犬第。
請這樣解決:
* Build Setting–> Apple LLVM 7.0 – Preprocessing–> Enable Strict Checking of objc_msgSend Calls 改為 NO
也可以這樣寫(推薦):
`((void(*)(id,SEL,id))objc_msgSend)(peopleInstance,s,@"大家好");`
強(qiáng)制轉(zhuǎn)換`objc_msgSend`函數(shù)類型為帶三個參數(shù)且返回值為void函數(shù)锦积,然后才能傳三個參數(shù)。

> ###案例小結(jié):
看看我們都干了什么歉嗓?丰介!What have we done?!O薄带膀!
此實(shí)戰(zhàn)內(nèi)容是,動態(tài)創(chuàng)建一個類橙垢,并創(chuàng)建成員變量和方法垛叨,最后賦值成員變量并發(fā)送消息。其中成員變量的賦值使用了KVC和object_setIvar函數(shù)兩種方式柜某,這些東西大家舉一反三就可以了

回顧一下: 1. OC元素的認(rèn)知 內(nèi)容 2. OC消息傳遞 機(jī)制 方法 案例演示
下一篇繼續(xù) [Runtime梳理(二)](http://www.reibang.com/p/6d685aeb0c4f)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗽元,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子莺琳,更是在濱河造成了極大的恐慌还棱,老刑警劉巖载慈,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惭等,死亡現(xiàn)場離奇詭異,居然都是意外死亡办铡,警方通過查閱死者的電腦和手機(jī)辞做,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寡具,“玉大人秤茅,你說我怎么就攤上這事⊥” “怎么了框喳?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長厦坛。 經(jīng)常有香客問我五垮,道長,這世上最難降的妖魔是什么杜秸? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任放仗,我火速辦了婚禮,結(jié)果婚禮上撬碟,老公的妹妹穿的比我還像新娘诞挨。我一直安慰自己,他們只是感情好呢蛤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布惶傻。 她就那樣靜靜地躺著,像睡著了一般其障。 火紅的嫁衣襯著肌膚如雪银室。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音粮揉,去河邊找鬼巡李。 笑死,一個胖子當(dāng)著我的面吹牛扶认,可吹牛的內(nèi)容都是我干的侨拦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辐宾,長吁一口氣:“原來是場噩夢啊……” “哼狱从!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叠纹,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤季研,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后誉察,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體与涡,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年持偏,在試婚紗的時候發(fā)現(xiàn)自己被綠了驼卖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸿秆,死狀恐怖酌畜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卿叽,我是刑警寧澤桥胞,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站考婴,受9級特大地震影響贩虾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕉扮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一整胃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喳钟,春花似錦屁使、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至易茬,卻和暖如春酬蹋,著一層夾襖步出監(jiān)牢的瞬間及老,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工范抓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骄恶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓匕垫,卻偏偏與公主長得像僧鲁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子象泵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

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

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