RunTime簡介:
RunTime簡稱運(yùn)行時戏锹。OC就是運(yùn)行時機(jī)制斜棚,也就是運(yùn)行時候的一些機(jī)制,其中最主要的就是消息機(jī)制啄育。
對于C語言酌心,函數(shù)的調(diào)用在編譯的時候就會決定調(diào)用哪個函數(shù),如果調(diào)用未實(shí)現(xiàn)的函數(shù)就會報錯灸撰。對于OC語言谒府,他是一門動態(tài)的語言拼坎,因?yàn)樗诰幾g的時候并不能決定真正調(diào)用的是哪個函數(shù),只有在真正運(yùn)行的時候才會根據(jù)函數(shù)的名稱找到對應(yīng)的函數(shù)進(jìn)行調(diào)用完疫。在編譯階段泰鸡,OC可以調(diào)用任何函數(shù),即使這個函數(shù)并未實(shí)現(xiàn)壳鹤,只要聲明過就不會報錯盛龄。
RunTime消息機(jī)制
消息機(jī)制是運(yùn)行時里面最重要的機(jī)制,OC中任何方法的調(diào)用芳誓,本質(zhì)都是發(fā)送消息余舶。
@selector(SEL):
這是一個方法選擇器。主要作用是快速的通過方法名字查找到對應(yīng)方法的函數(shù)指針锹淌,然后調(diào)用其函數(shù)也就是IMP匿值。SEL其本身是一個Int類型的地址,地址中存放著方法名字赂摆。對于一個類中挟憔,每一個方法對應(yīng)著一個SEL。所以一個類中不能存在兩個名稱相同的方法烟号,即使參數(shù)類型不同也不行绊谭,因?yàn)镾EL是根據(jù)方法名字生成的,相同的方法名稱只能對應(yīng)一個SEl汪拥。
實(shí)例方法和類方法的調(diào)用過程
實(shí)例方法的調(diào)用過程:首先會根據(jù)實(shí)例對象的isa指針找到他的類對象达传,在類對象的對象方法列表中去查找是否有對應(yīng)實(shí)現(xiàn),如果有就調(diào)用迫筑,沒有就依次去類對象的父類中查找宪赶,一直找到NSObject還沒有的話會進(jìn)入消息轉(zhuǎn)發(fā),如果在消息轉(zhuǎn)發(fā)流程(其中有三個方法)還是沒有做處理铣焊,就會報找不到方法異常逊朽。
類方法的調(diào)用過程:首先也是會根據(jù)類對象的isa指針找到它的元類,元類中存儲著類方法列表曲伊,如果當(dāng)前元類的類方法列表沒有叽讳,再依次去元類的父類中查找對應(yīng)實(shí)現(xiàn),一直找到根元類坟募,還是沒有的話岛蚤,這個時候與實(shí)例方法調(diào)用不同的是,如果類對象里面有同名的實(shí)例方法懈糯,就回去調(diào)用同名的實(shí)例方法涤妒。如果沒有在進(jìn)入消息轉(zhuǎn)發(fā),消息轉(zhuǎn)發(fā)沒做處理的話就會報找不到方法異常赚哗。
Runtime的應(yīng)用:
獲取列表
Method *methods = class_copyMethodList([UITextView class], &count);
for (int i = 0; i < count; i++) {
Method method = methods[i];
SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector);
NSLog(@"method_getName:%@",name);
}
unsigned int numIvars;
Ivar *vars = class_copyIvarList([UITextView class], &numIvars);
NSString *key=nil;
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = vars[i];
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
NSLog(@"variable_name :%@", key);
}
1.獲取列表(比如獲取類的屬性列表她紫,方法列表硅堆,成員變量列表)。比如實(shí)際開發(fā)中做歸檔解檔的時候?qū)ο蟮膶傩院芏嗟臅r候就可以用RunTime這個特性很方便的簡化代碼贿讹。
2.方法調(diào)用:正如上面所講的實(shí)例方法調(diào)用和類方法調(diào)用渐逃。
3.攔截調(diào)用:攔截調(diào)用就是,在找不到調(diào)用的方法程序奔潰之前民褂,你有機(jī)會通過重寫NSObject的四個方法來處理茄菊。
4.動態(tài)添加方法:如果一個類方法非常多,其中可能許多方法暫時用不到赊堪。而加載類方法到內(nèi)存的時候需要給每個方法生成映射表面殖,比較耗費(fèi)資源,這個時候就可以用Runtime動態(tài)添加方法哭廉。動態(tài)給某個類添加方法脊僚,相當(dāng)于懶加載機(jī)制,類中許多方法暫時用不到群叶,那么就先不加載吃挑,等用的時候再去加載钝荡。另外如果找不到對應(yīng)的方法時就會來到攔截調(diào)用街立,也就是因?yàn)檎也坏椒椒▽?shí)現(xiàn),在奔潰之前可以調(diào)用的方法埠通。當(dāng)調(diào)用了沒有實(shí)現(xiàn)的對象方法時赎离,就會調(diào)用+(BOOL)resolveInstanceMethod:(SEL)sel方法當(dāng)調(diào)用了沒有實(shí)現(xiàn)的類方法時,就會調(diào)用+(BOOL)resolveClassMethod:(SEL)sel方法端辱,我們就可以實(shí)現(xiàn)這兩個方法動態(tài)的給實(shí)例方法或者類方法添加方法和方法實(shí)現(xiàn)梁剔。
5.方法交換:當(dāng)系統(tǒng)自帶的方法功能不夠,需要給系統(tǒng)自帶的方法擴(kuò)展一些功能舞蔽,并且保持原有的功能時荣病,可以使用Runtime交換方法實(shí)現(xiàn)。這個特性可以用來處理開發(fā)中常見的奔潰(比如字典添加nil值渗柿,和數(shù)組越界等導(dǎo)致的奔潰)或者是統(tǒng)一添加埋點(diǎn)个盆,可以很方便的解決這些問題。