一、RunTime概念
RunTime簡稱運行時,我們總是聽說OC是動態(tài)語言運行時機制,也就是系統(tǒng)在運行時候的一些機制,其中最重要的是消息機制。C語言,函數(shù)的調(diào)用在編譯的時候會決定調(diào)用哪個函數(shù),如果調(diào)用未實現(xiàn)的函數(shù)就會報錯,而OC語言屬于動態(tài)調(diào)用過程,在編譯時并不能決定真正調(diào)用哪個函數(shù),只有在真正的運行的時候才會根據(jù)函數(shù)的名稱找到對應(yīng)函數(shù)來調(diào)用,當(dāng)調(diào)用該對象上某個方法,而該對象上沒有實現(xiàn)這個方法的時候,可以通過“消息轉(zhuǎn)發(fā)”進行解決,也就是說,在編譯截斷,OC可以調(diào)用任何函數(shù),即使是這個函數(shù)沒有實現(xiàn),只要聲明過就不會報錯。
二、OC調(diào)用方法在RunTime中的具體實現(xiàn)
《一》RunTime消息機制
消息機制是運行時里面最重要的機制,OC是動態(tài)語言,本質(zhì)都是發(fā)送消息,每個方法在運行時會被動態(tài)轉(zhuǎn)化為消息發(fā)送,即:objc_msgSend(receiver, selector)
比如:
- OC代碼實例方法調(diào)用底層的實現(xiàn):
BackView *backView = [[BackView alloc] init];
[backView changeBgColor];
//編譯時底層轉(zhuǎn)化
//objc對象的isa指針指向他的類對象,從而可以找到對象上的方法
//SEL:方法編號,根據(jù)方法編號就可以找到對應(yīng)方法的實現(xiàn)。
[backView performSelector:@selector(changeBgColor)];
//performSelector本質(zhì)即為運行時,發(fā)送消息,誰做事情就調(diào)用誰
objc_msgSend(backView, @selector(changeBgColor));
// 帶參數(shù)
objc_msgSend(backView, @selector(changeBgColor:),[UIColor RedColor]);
- OC代碼類方法調(diào)用底層的實現(xiàn)
//本質(zhì)是將類名轉(zhuǎn)化成類對象,初始化方法其實是創(chuàng)建類對象。
[BackView changeBgColor];
//BackView 只是表示一個類名,調(diào)用方法其實是用的類對象去調(diào)用的。(類對象既然稱為對象,那它也是一個實例。類對象中也有一個isa指針指向它的元類(meta class),即類對象是元類的實例。元類內(nèi)部存放的是類方法列表,根元類的isa指針指向自己,superclass指針指向NSObject類。)
//編譯時底層轉(zhuǎn)化
//RunTime 調(diào)用類方法同樣,類方法也是類對象去調(diào)用,所以需要獲取類對象,然后使用類對象去調(diào)用方法
Class backViewClass = [BackView class];
[backViewClass performSelector:@selector(changeBgColor)];
//performSelector本質(zhì)即為運行時,發(fā)送消息,誰做事情就調(diào)用誰
//類對象發(fā)送消息
objc_msgSend(backViewClass, @selector(changeBgColor));
// 帶參數(shù)
objc_msgSend(backViewClass, @selector(changeBgColor:),[UIColor RedColor]);
selector(SEL):是一個SEL方法選擇器。
SEL其主要作用是快速的通過SEL其主要作用是快速的通過方法名字查找到對應(yīng)方法的函數(shù)指針,然后調(diào)用其函數(shù)。SEL其本身是一個Int類型的地址,地址中存放著方法的名字。
對于一個類中。每一個方法對應(yīng)著一個SEL。所以一個類中不能存在2個名稱相同的方法,即使參數(shù)類型不同,因為SEL是根據(jù)方法名字生成的,相同的方法名稱只能對應(yīng)一個SEL。
- 消息傳遞的底層實現(xiàn)
這里我們要先說一下,一個Objc對象如何進行內(nèi)存布局的,我們先看一下objc_class源碼:
// runtime.h(類在runtime中的定義)
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指針指向Meta Class,因為Objc的類的本身也是一個Object,為了處理這個關(guān)系,runtime就創(chuàng)造了Meta Class,當(dāng)給類發(fā)送[NSObject alloc]這樣消息時,實際上是把這個消息發(fā)給了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本信息,默認為0
long info OBJC2_UNAVAILABLE; // 類信息,供運行期使用的一些位標(biāo)識
long instance_size OBJC2_UNAVAILABLE; // 該類的實例變量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量鏈表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法緩存,對象接到一個消息會根據(jù)isa指針查找消息對象,這時會在method Lists中遍歷,如果cache了,常用的方法調(diào)用時就能夠提高調(diào)用的效率。
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;
objc對象內(nèi)存布局:
<1>所有父類的成員變量和自己的成員變量都會存放在該對象所對應(yīng)的存儲空間中。
<2>每個對象內(nèi)部都有一個isa指針,指向它的類對象,類對象中存放著本對象的:
1、對象方法列表(對象能夠接受的消息列表,保存再它所對應(yīng)的類對象中)
2、成員變量的列表
3、屬性列表
每一個類都有一個方法列表Method List,保存著類里面所有的方法,根據(jù)SEL傳入的方法編號找到方法,然后找到方法的實現(xiàn),然后在方法的實現(xiàn)里面實現(xiàn)。
消息發(fā)送動態(tài)查找對應(yīng)的方法
<1>實例對象調(diào)用方法后,底層調(diào)用[objc performSelector:@selector(SEL)];方法,編譯器將代碼轉(zhuǎn)化為objc_msgSend(receiver, selector)。
<2>在objc_msgSend函數(shù)中,首先通過objc的isa指針找到objc對應(yīng)的class,在class中先去cache中通過SEL查找對應(yīng)函數(shù)的method,如果找到則通過method中的函數(shù)指針跳轉(zhuǎn)到對應(yīng)的函數(shù)中去執(zhí)行。
<3>如果在cacha中未找到,再去methodList中查找,如果能找到,則將method加入到cache中,以方便下次查找,并通過method中的函數(shù)指針跳轉(zhuǎn)到對應(yīng)的函數(shù)中去執(zhí)行。
<4>如果在methodlist中未找到,則去superClass中去查找,如果能找到,則將method加入到cache中,以方便下次查找,并通過method中的函數(shù)指針跳轉(zhuǎn)到對應(yīng)的函數(shù)中去執(zhí)行。-
消息傳遞的過程
<接上↑>objc在向一個對象發(fā)送消息時,runtime庫會根據(jù)對象的isa指針找到該對象實際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運行,即:objc_msgSend(receiver, selector)。如果,在最頂層的父類中依然找不到相應(yīng)的方法時,程序在運行時會掛掉并拋出異常unrecognized selector sent to XXX 。但是在這之前,objc的運行時會給出三次拯救程序崩潰的機會:
<1> Method resolution
objc運行時會調(diào)用+resolveInstanceMethod:或者+resolveClassMethod:(實例方法和類方法),讓你有機會提供一個函數(shù)實現(xiàn)。如果你添加了函數(shù),那運行時系統(tǒng)就會重新啟動一次消息發(fā)送的過程,否則 ,運行時就會移到下一步,消息轉(zhuǎn)發(fā)(Message Forwarding)。
<2> Message Forwarding-
<1>Fast forwarding
如果目標(biāo)對象實現(xiàn)了-forwardingTargetForSelector:,Runtime 這時就會調(diào)用這個方法,給你把這個消息轉(zhuǎn)發(fā)給其他對象的機會。 只要這個方法返回的不是nil和self,整個消息發(fā)送的過程就會被重啟,當(dāng)然發(fā)送的對象會變成你返回的那個對象。否則,就會繼續(xù)Normal Fowarding。 這里叫Fast,只是為了區(qū)別下一步的轉(zhuǎn)發(fā)機制。因為這一步不會創(chuàng)建任何新的對象,但下一步轉(zhuǎn)發(fā)會創(chuàng)建一個NSInvocation對象,所以相對更快點。 -
<2>Normal forwarding
這一步是Runtime最后一次給你挽救的機會。首先它會發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果-methodSignatureForSelector:返回nil,Runtime則會發(fā)出-doesNotRecognizeSelector:消息,程序這時也就掛掉了。如果返回了一個函數(shù)簽名,Runtime就會創(chuàng)建一個NSInvocation對象并發(fā)送-forwardInvocation:消息給目標(biāo)對象。
-
<1>Fast forwarding
《二》使用RunTime動態(tài)的添加對象的成員變量和方法
-
動態(tài)添加方法
動態(tài)給某各類添加方法,相當(dāng)于懶加載機制。這里我們以實例方法為例,首先我們先不實現(xiàn)對象方法,當(dāng)調(diào)用performSelector:方法的時候,再去動態(tài)加載方法調(diào)用。[bg performSelector:@selector(changeBgColor)];當(dāng)編譯時是不會報錯的,運行時才會報錯,因為這里我們BaseView類中并沒有實現(xiàn)changeBgColor這個方法,當(dāng)去類的Method List中發(fā)現(xiàn)找不到changeBgColor方法,會報錯找不到這個方法。這里我們就用到了上面提到的消息轉(zhuǎn)發(fā)機制。當(dāng)調(diào)用了沒有實現(xiàn)的對象方法時,就會調(diào)用+(BOOL)resolveInstanceMethod:(SEL)sel方法,當(dāng)調(diào)用了沒有實現(xiàn)的類方法的時候,就會調(diào)用+(BOOL)resolveClassMethod:(SEL)sel方法。所以通過這兩個方法就可以動態(tài)添加方法,參數(shù)sel即表示沒有實現(xiàn)的方法。一個objective - C方法最終都是一個C函數(shù),默認任何一個方法都有兩個參數(shù)。self : 方法調(diào)用者 _cmd : 調(diào)用方法編號。我們可以使用函數(shù)class_addMethod為類添加一個方法以及實現(xiàn)。
動態(tài)添加方法:
+(BOOL)resolveInstanceMethod:(SEL)sel
{
// 動態(tài)添加changeBgColor方法
// 首先判斷sel是不是changeBgColor方法 也可以轉(zhuǎn)化成字符串進行比較。
if (sel == @selector(changeBgColor)) {
/**
第一個參數(shù): cls:給哪個類添加方法
第二個參數(shù): SEL name:添加方法的編號
第三個參數(shù): IMP imp: 方法的實現(xiàn),函數(shù)入口,函數(shù)名可與方法名不同(建議與方法名相同)
第四個參數(shù): types :方法類型,需要用特定符號,參考API
*/
class_addMethod(self, sel, (IMP) newChangeBgColor , "v@:");
// 處理完返回YES
return YES;
}
return [super resolveInstanceMethod:sel];
}
void newChangeBgColor(id self ,SEL _cmd)
{
}
types:方法類型表:

-
動態(tài)添加變量
1-> 動態(tài)獲取類中的所有屬性(包括私有)
Ivar *ivar = class_copyIvarList([self.baseView class], &count);
2->遍歷屬性找到對應(yīng)屬性字段
const char *varName = ivar_getName(var);
3->修改對應(yīng)的字段
object_setIvar(self.baseView, var, @"newName");
具體:
-(void)addNewName{
unsigned int count = 0;
Ivar *ivar = class_copyIvarList([baseView class], &count);
for (int i = 0; i<count; i++) {
Ivar var = ivar[i];
const char *varName = ivar_getName(var);
NSString *name = [NSString stringWithUTF8String:varName];
if ([name isEqualToString:@"oldName"]) {
object_setIvar(baseView, var, @"newName");
break;
}
}
self.nameLabel.text = baseView.oldName;
}
《三》動態(tài)交換方法
當(dāng)遇到所使用的系統(tǒng)方法或者不可修改的靜態(tài)庫方法功能不夠時,需要給此類方法擴展一些功能。比如我們有個BaseView類中有個changeBgColor的方法,此時我們想在這個方法里做些操作,我們定義一個newChangeBgColor的方法。因為交換只需進行一次,所以我們在BaseView的Categary中的load方法中,當(dāng)加載分類的時候交換方法即可。交換方法的本質(zhì)其實是交換兩個方法的實現(xiàn)
即:
1根據(jù)SEL方法編號在Method List中找到方法
2交換兩個IMP指針指向的方法實現(xiàn)

+(void)load
{
// 獲取要交換的兩個方法
// 獲取類方法 用Method 接受一下
// class :獲取哪個類方法
// SEL :獲取方法編號,根據(jù)SEL就能去對應(yīng)的類找方法。
Method oldChangeColorMethod = class_getClassMethod([UIImage class], @selector(changeBgColor));
// 獲取第二個類方法
Method newChangeColorMethod = class_getClassMethod([UIImage class], @selector(newChangeBgColor));
// 交換兩個方法的實現(xiàn) 方法一 ,方法二。
method_exchangeImplementations(oldChangeColorMethod, newChangeColorMethod);
// IMP其實就是 implementation的縮寫:表示方法實現(xiàn)。
}
注意:交換方法的時候newMethod里就不能再調(diào)用oldMethod方法了,因為調(diào)用oldMethod方法實質(zhì)上相當(dāng)于調(diào)用newMethod方法,會循環(huán)引用造成死循環(huán)。
《四》RunTim動態(tài)添加屬性
XCode運行在Category的.h文件聲明@property編譯通過,但運行時如果沒有runtime處理,進行賦值取值,就會報錯。
-
@property的本質(zhì)是什么
@property = ivar + getter + setter;
說人話:
“屬性”(property)有兩大概念:ivar(實例變量)、存取方法(access method = getter + setter)。
“屬性”(property)作為OC的一項特性,主要的作用就在于封裝對象總的數(shù)據(jù)。OC 對象通常會把其所需要的數(shù)據(jù)保存為各種實例變量,實例變量一般通過“存取方法”(access method)來訪問,其中,“獲取方法”(getter)用于讀取變量值,而“設(shè)置方法”(setter)用于寫入變量值。在正規(guī)的OC編碼風(fēng)格中,存取方法有著嚴格的命名規(guī)范,正因為有了這種嚴格的命名規(guī)范,所以O(shè)C可以根據(jù)名稱自動創(chuàng)建出存取方法,其實也可以把屬性當(dāng)做一種關(guān)鍵字,可以表示:
編譯器會自動寫出一套存取方法,用以訪問給定類型中具有給定名稱的變量,所以你也可以這么說:@property=getter+setter;
比如下面的這個類:
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
上述代碼寫出來的類與下面這種寫法等效:
@interface Person : NSObject
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;
@end
而objc_property是一個結(jié)構(gòu)體,包括name和attributes,定義如下:
struct property_t {
const char *name;
const char *attributes;
};
而attributes本質(zhì)是objc_property_attribute_t,定義了property的一些屬性,定義如下:
/// Defines a property attribute
typedef struct {
const char *name; /**< The name of the attribute */
const char *value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
而attributes的具體內(nèi)容是什么呢?其實,包括:類型,原子性,內(nèi)存語義和對應(yīng)的實例變量。
例如:我們定義一個string的property@property (nonatomic, copy) NSString *string;
,通過 property_getAttributes(property)
獲取到attributes并打印出來之后的結(jié)果為T@"NSString",C,N,V_string
其中T就代表類型,可參閱Type Encodings,C就代表Copy,N代表nonatomic,V就代表對于的實例變量。
ivar、getter、setter 是如何生成并添加到這個類中的?
“自動合成”( autosynthesis)
完成屬性定義后,編譯器會自動編寫訪問這些屬性所需的方法,此過程叫做“自動合成”(autosynthesis)。需要強調(diào)的是,這個過程由編譯 器在編譯期執(zhí)行,所以編輯器里看不到這些“合成方法”(synthesized method)的源代碼。除了生成方法代碼 getter、setter 之外,編譯器還要自動向類中添加適當(dāng)類型的實例變量,并且在屬性名前面加下劃線,以此作為實例變量的名字。在前例中,會生成兩個實例變量,其名稱分別為 _firstName 與 _lastName。也可以在類的實現(xiàn)代碼里通過 @synthesize 語法來指定實例變量的名字.
@implementation Person
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
屬性是怎么實現(xiàn)的呢?
1、OBJC_IVAR_$類名$屬性名稱 :該屬性的“偏移量” (offset),這個偏移量是“硬編碼” (hardcode),表示該變量距離存放對象的內(nèi)存區(qū)域的起始地址有多遠。
2、setter 與 getter 方法對應(yīng)的實現(xiàn)函數(shù)
3、ivar_list :成員變量列表
4、method_list :方法列表
5、prop_list :屬性列表
也就是說我們每次在增加一個屬性,系統(tǒng)都會在 ivar_list 中添加一個成員變量的描述,在 method_list 中增加 setter 與 getter 方法的描述,在屬性列表中增加一個屬性的描述,然后計算該屬性在對象中的偏移量,然后給出 setter 與 getter 方法對應(yīng)的實現(xiàn),在 setter 方法中從偏移量的位置開始賦值,在 getter 方法中從偏移量開始取值,為了能夠讀取正確字節(jié)數(shù),系統(tǒng)對象偏移量的指針類型進行了類型強轉(zhuǎn).
如何在@protocol和category中使用@property?
1、在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對象能實現(xiàn)該屬性
2、category 使用 @property 也是只會生成 setter 和 getter 方法的聲明,但是不會自動生成私有屬性,如果我們真的需要給 category 增加屬性的實現(xiàn),需要借助于運行時的兩個函數(shù):
1、動態(tài)添加屬性
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
參數(shù)一:id object : 給哪個對象添加屬性,這里要給自己添加屬性,用self。
參數(shù)二:void * == id key : 屬性名,根據(jù)key獲取關(guān)聯(lián)對象的屬性的值,在objc_getAssociatedObject中通過次key獲得屬性的值并返回。
參數(shù)三:id value : 關(guān)聯(lián)的值,也就是set方法傳入的值給屬性去保存。
參數(shù)四:objc_AssociationPolicy policy : 策略,屬性以什么形式保存。
>>>>>
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, // 指定一個弱引用相關(guān)聯(lián)的對象
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 指定相關(guān)對象的強引用,非原子性
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, // 指定相關(guān)的對象被復(fù)制,非原子性
OBJC_ASSOCIATION_RETAIN = 01401, // 指定相關(guān)對象的強引用,原子性
OBJC_ASSOCIATION_COPY = 01403 // 指定相關(guān)的對象被復(fù)制,原子性
};
獲得屬性
objc_getAssociatedObject(id object, const void *key);
參數(shù)一:id object : 獲取哪個對象里面的關(guān)聯(lián)的屬性。
參數(shù)二:void * == id key : 什么屬性,與objc_setAssociatedObject中的key相對應(yīng),即通過key值取出value。
此時已經(jīng)成功給NSObject添加name屬性,并且NSObject對象可以通過點語法為屬性賦值。
下面這個也是一樣的:
-(void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @"name",name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)name
{
return objc_getAssociatedObject(self, @"name");
}
《RunTime字典轉(zhuǎn)模型》
通過給NSObject添加分類,聲明并實現(xiàn)使用Runtime字典轉(zhuǎn)模型的類方法:
+ (instancetype)modelWithDict:(NSDictionary *)dict
KVC字典轉(zhuǎn)模型和RunTime轉(zhuǎn)模型的區(qū)別:
KVC:KVC字典轉(zhuǎn)模型實現(xiàn)原理是遍歷字典中所有Key,然后去模型中查找相對應(yīng)的屬性名,要求屬性名與Key必須一一對應(yīng),字典中所有key必須在模型中存在。
RunTime:RunTime字典轉(zhuǎn)模型實現(xiàn)原理是遍歷模型中的所有屬性名,然后去字典查找相對應(yīng)的Key,也就是以模型為準,模型中有哪些屬性,就去字典中找那些屬性。
RunTime字典轉(zhuǎn)模型的優(yōu)點:當(dāng)服務(wù)器返回的數(shù)據(jù)過多,而我們只使用其中很少一部分時,沒有用的屬性就沒有必要定義成屬性浪費不必要的資源。只保存最有用的屬性即可。
字典轉(zhuǎn)模型簡要過程:
1、創(chuàng)建模型對象
2、使用class_copyIvarList方法copy成員屬性列表
unsigned int count = 0;
Ivar *ivarList = class_copyIvarList(self, &count);
參數(shù)一:__unsafe_unretained Class cls : 獲取哪個類的成員屬性列表。這里是self,因為誰調(diào)用分類中類方法,誰就是self。
參數(shù)二:unsigned int *outCount : 無符號int型指針,這里創(chuàng)建unsigned int型count,&count就是他的地址,保證在方法中可以拿到count的地址為count賦值。傳出來的值為成員屬性總數(shù)。
返回值:Ivar * : 返回的是一個Ivar類型的指針 。指針默認指向的是數(shù)組的第0個元素,指針+1會向高地址移動一個Ivar單位的字節(jié),也就是指向第一個元素。Ivar表示成員屬性。
3、遍歷成員屬性列表,獲得屬性列表
for (int i = 0 ; i < count; i++) {
// 獲取成員屬性
Ivar ivar = ivarList[i];
}
4、使用ivar_getName(ivar)獲得成員屬性名,因為成員屬性名返回的是C語言字符串,將其轉(zhuǎn)化成OC 字符串
NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
或者ivar_getTypeEncoding(ivar)方法
5、獲得的成員屬性名是帶的成員屬性,去掉,獲得屬性名,也就是字典的key。
// 獲取key
NSString *key = [propertyName substringFromIndex:1];
6、獲取字典中key對應(yīng)的Value。
id value = dict[key];
7、給模型屬性賦值,并將模型返回
if (value) {
// KVC賦值:不能傳空
[objc setValue:value forKey:key];
}
return objc;
二級模型轉(zhuǎn)化方法:
+ (instancetype)modelWithDict:(NSDictionary *)dict{
// 1.創(chuàng)建對應(yīng)類的對象
id objc = [[self alloc] init];
// count:成員屬性總數(shù)
unsigned int count = 0;
// 獲得成員屬性列表和成員屬性數(shù)量
Ivar *ivarList = class_copyIvarList(self, &count);
for (int i = 0 ; i < count; i++) {
// 獲取成員屬性
Ivar ivar = ivarList[i];
// 獲取成員名
NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
// 獲取key
NSString *key = [propertyName substringFromIndex:1];
// 獲取字典的value key:屬性名 value:字典的值
id value = dict[key];
// 獲取成員屬性類型
NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
// 二級轉(zhuǎn)換
// value值是字典并且成員屬性的類型不是字典,才需要轉(zhuǎn)換成模型
if ([value isKindOfClass:[NSDictionary class]] && ![propertyType containsString:@"NS"]) {
// 進行二級轉(zhuǎn)換
// 獲取二級模型類型進行字符串截取,轉(zhuǎn)換為類名
NSRange range = [propertyType rangeOfString:@"\""];
propertyType = [propertyType substringFromIndex:range.location + range.length];
range = [propertyType rangeOfString:@"\""];
propertyType = [propertyType substringToIndex:range.location];
// 獲取需要轉(zhuǎn)換類的類對象
Class modelClass = NSClassFromString(propertyType);
// 如果類名不為空則進行二級轉(zhuǎn)換
if (modelClass) {
// 返回二級模型賦值給value
value = [modelClass modelWithDict:value];
}
}
if (value) {
// KVC賦值:不能傳空
[objc setValue:value forKey:key];
}
}
// 返回模型
return objc;
}
總結(jié)
上述對RunTime的總結(jié)只是一些自己平時的積累,借鑒了一些好的博文資料加上自己的一些理解,還有很多東西沒有理解到位,還請多多指教。