runtime的用法
RunTime簡(jiǎn)稱運(yùn)行時(shí)。就是系統(tǒng)在運(yùn)行的時(shí)候的一些機(jī)制,其中最主要的是消息機(jī)制。對(duì)于C語言,函數(shù)的調(diào)用在編譯的時(shí)候會(huì)決定調(diào)用哪個(gè)函數(shù)( C語言的函數(shù)調(diào)用請(qǐng)看這里 )。編譯完成之后直接順序執(zhí)行,無任何二義性。OC的函數(shù)調(diào)用成為消息發(fā)送。屬于動(dòng)態(tài)調(diào)用過程。在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)(事實(shí)證明,在編 譯階段,OC可以調(diào)用任何函數(shù),即使這個(gè)函數(shù)并未實(shí)現(xiàn),只要申明過就不會(huì)報(bào)錯(cuò)。而C語言在編譯階段就會(huì)報(bào)錯(cuò))。只有在真正運(yùn)行的時(shí)候才會(huì)根據(jù)函數(shù)的名稱找 到對(duì)應(yīng)的函數(shù)來調(diào)用。
那OC是怎么實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的呢?下面我們來看看OC通過發(fā)送消息來達(dá)到動(dòng)態(tài)調(diào)用的秘密。假如在OC中寫了這樣的一個(gè)代碼:
| 1 | [obj?makeText]; |
其中obj是一個(gè)對(duì)象,makeText是一個(gè)函數(shù)名稱。對(duì)于這樣一個(gè)簡(jiǎn)單的調(diào)用。在編譯時(shí)RunTime會(huì)將上述代碼轉(zhuǎn)化成
| 1 | objc_msgSend(obj,@selector(makeText)); |
首先我們來看看obj這個(gè)對(duì)象,iOS中的obj都繼承于NSObject。
| 1 2 3 | @interface?NSObject?<nsobject>?{ ????Class?isa??OBJC_ISA_AVAILABILITY; }</nsobject> |
在NSObjcet中存在一個(gè)Class的isa指針。然后我們看看Class:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | typedef?struct?objc_class?*Class; struct?objc_class?{ ??Class?isa;?//?指向metaclass ??? ??Class?super_class?;?//?指向其父類 ??const?char?*name?;?//?類名 ??long?version?;?//?類的版本信息,初始化默認(rèn)為0,可以通過runtime函數(shù)class_setVersion和class_getVersion進(jìn)行修改、讀取 ??long?info;?//?一些標(biāo)識(shí)信息,如CLS_CLASS?(0x1L)?表示該類為普通?class?,其中包含對(duì)象方法和成員變量;CLS_META?(0x2L)?表示該類為?metaclass,其中包含類方法; ??long?instance_size?;?//?該類的實(shí)例變量大小(包括從父類繼承下來的實(shí)例變量); ??struct?objc_ivar_list?*ivars;?//?用于存儲(chǔ)每個(gè)成員變量的地址 ??struct?objc_method_list?**methodLists?;?//?與?info?的一些標(biāo)志位有關(guān),如CLS_CLASS?(0x1L),則存儲(chǔ)對(duì)象方法,如CLS_META?(0x2L),則存儲(chǔ)類方法; ??struct?objc_cache?*cache;?//?指向最近使用的方法的指針,用于提升效率; ??struct?objc_protocol_list?*protocols;?//?存儲(chǔ)該類遵守的協(xié)議 ????} |
?
我們可以看到,對(duì)于一個(gè)Class類中,存在很多東西,下面我來一一解釋一下:
Class isa:指向metaclass,也就是靜態(tài)的Class。一般一個(gè)Obj對(duì)象中的isa會(huì)指向普通的Class,這個(gè)Class中存儲(chǔ)普通成員變量和對(duì) 象方法(“-”開頭的方法),普通Class中的isa指針指向靜態(tài)Class,靜態(tài)Class中存儲(chǔ)static類型成員變量和類方法(“+”開頭的方 法)。
Class super_class:指向父類,如果這個(gè)類是根類,則為NULL。
注意:所有metaclass中isa指針都指向跟metaclass。而跟metaclass則指向自身。Root metaclass是通過繼承Root class產(chǎn)生的。與root class結(jié)構(gòu)體成員一致,也就是前面提到的結(jié)構(gòu)。不同的是Root metaclass的isa指針指向自身。
Class類中其他的成員這里就先不做過多解釋了,下面我們來看看:
@selector (makeText):這是一個(gè)SEL方法選擇器。SEL其主要作用是快速的通過方法名字(makeText)查找到對(duì)應(yīng)方法的函數(shù)指針,然后調(diào)用其函 數(shù)。SEL其本身是一個(gè)Int類型的一個(gè)地址,地址中存放著方法的名字。對(duì)于一個(gè)類中。每一個(gè)方法對(duì)應(yīng)著一個(gè)SEL。所以iOS類中不能存在2個(gè)名稱相同 的方法,即使參數(shù)類型不同,因?yàn)镾EL是根據(jù)方法名字生成的,相同的方法名稱只能對(duì)應(yīng)一個(gè)SEL。
下面我們就來看看具體消息發(fā)送之后是怎么來動(dòng)態(tài)查找對(duì)應(yīng)的方法的。
首先,編譯器將代碼[obj makeText];轉(zhuǎn)化為objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數(shù)中。首先通過obj的isa指針找到obj對(duì)應(yīng)的class。在Class中先去cache中 通過SEL查找對(duì)應(yīng)函數(shù)method(猜測(cè)cache中method列表是以SEL為key通過hash表來存儲(chǔ)的,這樣能提高函數(shù)查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,并通過method中的函數(shù)指針跳轉(zhuǎn)到對(duì)應(yīng)的函數(shù)中去執(zhí)行。
下面總結(jié)我用到的一些runtime的例子.
1.找到類的屬性
?
? ?unsigned int count = 0;
? ? Ivar *ivar = class_copyIvarList([Obj class], &count);
?
? ? for (int i = 0; i<count; i++) {
? ? ? ? Ivar var = ivar[i];
? ? ? ? const char *varName = ivar_getName(var);
? ? ? ? NSString *objname = [NSString stringWithUTF8String:varName];
?? ? ? ?
? ? ? ? if ([objname isEqualToString:@"_name"]) { ? //這里別忘了給屬性加下劃線
? ? ? ? ? ? object_setIvar(obj, var, @"string");
? ? ? ? ? ? break;
? ? ? ? }
? ? }
2.找類中的方法(包括私有方法)
?unsigned int count=0;
?? ?
? ? Method * methodlist=class_copyMethodList([obj class], &count);
?? ?
? ? for (int i=0; i<count; i++) {
?? ? ? ?
? ? ? ? SEL methodname=method_getName(methodlist[i]);
?? ? ? ?
? ? ? ? NSString * methodstring=[NSString stringWithCString:sel_getName(methodname) encoding:NSUTF8StringEncoding];
?? ? ? ?
? ? ? ? NSLog(@"打印方法=%@",methodstring);
?? ? ? ?
? ? ? ? Method method1=class_getClassMethod([obj class], methodname);
?? ? ? ?
? ? ? ? }
? ? ??
?
3.添加方法
?class_addMethod([obj class], @selector(guessperson), (IMP)guessAnswer, "v@:");
? ? if ([self.person respondsToSelector:@selector(guessperson)]) {
? ? ? ? //Method method = class_getInstanceMethod([obj1 class], @selector(guess));
? ? ? ? [self.person performSelector:@selector(guessperson)];
?? ? ? ?
? ? } else{
? ? ? ? NSLog(@"Sorry,I don't know");
? ? }
void guessAnswer(id self,SEL _cmd){
?? ?
? ? NSLog(@"i am from beijing");
}
4.交換方法:
??Method m1 = class_getInstanceMethod([obj class], @selector(sayName));//找到實(shí)例方法
? ? Method m2 = class_getInstanceMethod([obj class], @selector(saySex));
? ? Method m3 = class_getClassMethod([obj class], @selector(selfwrite));//獲取類方法
? ? Method m4 = class_getInstanceMethod([obj class], @selector(sayName));
??
method_exchangeImplementations(m1, m2);//交換兩個(gè)方法,即方法m1執(zhí)行m2的方法,m2執(zhí)行m1的方法
?
轉(zhuǎn)載于:https://www.cnblogs.com/fucw/p/6651057.html
總結(jié)
以上是生活随笔為你收集整理的runtime的用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UploadFtp
- 下一篇: 汽车大灯同款灯,八近六元和六近八元的布局