iOS的runtime运行时机制
本文轉(zhuǎn)自http://www.cnblogs.com/guoxiao/p/3583432.html
最近一直在研究runtime運(yùn)行時機(jī)制的問題,我想可能也有很多人不太清楚這個問題吧?在這里跟大家溝通分享下我對與runtime機(jī)制的理解。
? 要理解runtime,首先我們要了解類和對象的內(nèi)部結(jié)構(gòu),下面將首先介紹下OC中類與對象的結(jié)構(gòu)層次。
? 一、首先,從?runtime.h頭文件中找到對 class 與 object 的定義
/// An opaque type that represents an Objective-C class. typedef struct objc_class *Class;/// Represents an instance of a class. struct objc_object {Class isa; };/// A pointer to an instance of a class. typedef struct objc_object *id;? 由此可見,Class是一個指向objc_class結(jié)構(gòu)體的指針,而id是一個指向objc_object結(jié)構(gòu)體的指針,其成員isa是一個指向objec_class結(jié)構(gòu)體的指針。
? 二、下面我們再看看頭文件中關(guān)于objc_class的定義
struct objc_class {Class isa; // 指向metaclassClass super_class ; // 指向其父類const char *name ; // 類名long version ; // 類的版本信息,初始化默認(rèn)為0,可以通過runtime函數(shù)class_setVersion和class_getVersion進(jìn)行修改、讀取long info; // 一些標(biāo)識信息,如CLS_CLASS (0x1L) 表示該類為普通 class ,其中包含對象方法和成員變量;CLS_META (0x2L) 表示該類為 metaclass,其中包含類方法;long instance_size ; // 該類的實(shí)例變量大小(包括從父類繼承下來的實(shí)例變量);struct objc_ivar_list *ivars; // 用于存儲每個成員變量的地址struct objc_method_list **methodLists ; // 與 info 的一些標(biāo)志位有關(guān),如CLS_CLASS (0x1L),則存儲對象方法,如CLS_META (0x2L),則存儲類方法;struct objc_cache *cache; // 指向最近使用的方法的指針,用于提升效率;struct objc_protocol_list *protocols; // 存儲該類遵守的協(xié)議}? 由此可見,類比對象的結(jié)構(gòu)體中多了眾多的成員,下面詳細(xì)介紹下objec_class中各成員:
isa:objec_object(對象)中isa指針指向的類結(jié)構(gòu)稱為class(也就是該對象所屬的類),其中存放著普通成員變量與對象方法 (“-”開頭的方法);然而此處isa指針指向的類結(jié)構(gòu)稱為metaclass,其中存放著static類型的成員變量與static類型的方法 (“+”開頭的方法)。
super_class: 指向該類的父類的指針,如果該類是根類(如NSObject或NSProxy),那么super_class就為NULL。
? 下面,我們通過一幅圖可以看清楚OC中類與對象的繼承層次關(guān)系:
?
?
注意:所有的metaclass中isa指針都是指向根metaclass,而根metaclass則指向自身。根metaclass是通過繼承根類產(chǎn)生的,與根class結(jié)構(gòu)體成員一致,不同的是根metaclass的isa指針指向自身。
1、當(dāng)我們調(diào)用某個對象的對象方法時,它會首先在自身isa指針指向的類(class)methodLists中查找該方法,如果找不到則會通過class的super_class指針找到其父類,然后從其methodLists中查找該方法,如果仍然找不到,則繼續(xù)通過 super_class向上一級父類結(jié)構(gòu)體中查找,直至根class;
2、當(dāng)我們調(diào)用某個類方法時,它會首先通過自己的isa指針找到metaclass,并從其methodLists中查找該類方法,如果找不到則會通過metaclass的super_class指針找到父類的metaclass結(jié)構(gòu)體,然后從methodLists中查找該方法,如果仍然找不到,則繼續(xù)通過super_class向上一級父類結(jié)構(gòu)體中查 找,直至根metaclass;
?
? 經(jīng)過以上介紹,相信你已經(jīng)對OC中對象與類的結(jié)構(gòu)層次有了進(jìn)一步的認(rèn)識。后面將會介紹如何使用runtime機(jī)制。
?
由于OC是運(yùn)行時語言,只有在程序運(yùn)行時,才會去確定對象的類型,并調(diào)用類與對象相應(yīng)的方法。利用runtime機(jī)制讓我們可以在程序運(yùn)行時動態(tài)修改類、對象中的所有屬性、方法。
??下面就介紹運(yùn)行時一種很簡單的使用方式,將字典對象轉(zhuǎn)為模型。當(dāng)然,你可能會問,我用KVO直接調(diào)用 setValuesForKeysWithDictionary:方法,傳入一個字典一樣可以快速將字典轉(zhuǎn)模型啊,但是這種方法有它的弊端,只有遍歷某個模型中所有的成員變量,然后通過成員變量從字典中取出對應(yīng)的值并賦值最為穩(wěn)妥,否則,當(dāng)模型中的屬性數(shù)量與字典中的key的數(shù)量不一樣時,就會報(bào)錯。而且,由于runtime是更底層的語言,我們編寫的OC代碼在運(yùn)行時,編譯器內(nèi)部會先轉(zhuǎn)為C和C++的代碼,然后再執(zhí)行,因而運(yùn)用runtime機(jī)制,程序的性能也會更好。說了這么多,下面就初步認(rèn)識一下runtime的強(qiáng)大。
? 首先,我們定義一個類
@interface Person : NSObject{CGFloat height; }@property (nonatomic, copy) NSString *name; @property (nonatomic, strong) NSNumber *age; @property (nonatomic, assign) int no;@end? 然后,我們在其它文件中使用這個類,注意在使用之前,要包含?#import <objc/message.h>
?下面通過一小段代碼來獲取到上面這個類中所有的成員變量
unsigned int outCount = 0;Ivar *vars = class_copyIvarList([Lender class], &outCount); // 獲取到所有的成員變量列表// 遍歷所有的成員變量for (int i = 0; i < outCount; i++) {Ivar ivar = vars[i]; // 取出第i個位置的成員變量const char *propertyName = ivar_getName(ivar); // 獲取變量名const char *propertyType = ivar_getTypeEncoding(ivar); // 獲取變量編碼類型printf("---%s--%s\n", propertyName, propertyType);}打印結(jié)果:
---height--f ---_name--@"NSString" ---_age--@"NSNumber" ---_no--i可見,通過上面幾句簡單的代碼就可以獲取到某個類中所有變量的名稱和類型,然后通過object_setIvar()方法為具體某個對象的某個成員變量賦值。
轉(zhuǎn)載于:https://www.cnblogs.com/jerny/p/3904976.html
總結(jié)
以上是生活随笔為你收集整理的iOS的runtime运行时机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【vbs】vbs写ini文件
- 下一篇: Photoshop脚本指南——Hello