Runtime的定義
//對象
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
//類
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
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;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
isa Class對象,指向objc_class結構體的指針,也就是這個Class的MetaClass(元類)
- 類的實例對象的 isa 指向該類;該類的 isa 指向該類的 MetaClass
- MetaCalss的isa對象指向RootMetaCalss
- 如果MetaClass是RootMetaCalss,那么該MetaClass的isa指針指向它自己
super_class Class對象指向父類對象
- 如果該類的對象已經是RootClass,那么這個super_class指向nil
- MetaCalss的SuperClass指向父類的MetaCalss
-
MetaCalss是RootMetaCalss,那么該MetaClass的SuperClass指向該對象的RootClass
如下圖:
1782258-47255d12d9681371.png
ivars: 類中所有屬性的列表,使用場景:我們在字典轉換成模型的時候需要用到這個列表找到屬性的名稱,去取字典中的值,KVC賦值,或者直接Runtime賦值
methodLists: 類中所有的方法的列表,類中所有方法的列表,使用場景:如在程序中寫好方法,通過外部獲取到方法名稱字符串,然后通過這個字符串得到方法,從而達到外部控制App已知方法。
cache: 主要用于緩存常用方法列表,每個類中有很多方法,我平時不用的方法也會在里面,每次運行一個方法,都要去methodLists遍歷得到方法,如果類的方法不多還行,但是基本的類中都會有很多方法,這樣勢必會影響程序的運行效率,所以cache在這里就會被用上,當我們使用這個類的方法時先判斷cache是否為空,為空從methodLists找到調用,并保存到cache,不為空先從cache中找方法,如果找不到在去methodLists,這樣提高了程序方法的運行效率
protocols: 故名思義,這個類中都遵守了哪些協議,使用場景:判斷類是否遵守了某個協議上
//方法列表
struct objc_method_list {
struct objc_method_list *obsolete OBJC2_UNAVAILABLE;
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
//方法
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
?
?
?
Runtime消息轉發
調用方法時,先消息傳遞,沒搜到再轉發,沒有轉發就用崩潰。
消息傳遞:分類(先緩存表后方法表)->當前類->父類->NSObject
消息轉發:動態方法解析->備用接收者->完整消息轉發
?
?
?
Runtime常用方法
// 動態獲取類中的所有屬性(包括私有)
Ivar *ivar = class_copyIvarList(_person.class, &count);
// 修改對應的字段值
object_setIvar(_person, tempIvar, @"更改屬性值成功");
//動態添加方法
class_addMethod([_person class], @selector(coding), (IMP)codingOC, "v@:");
//方法交換(避免崩潰)
// 判斷自定義的方法是否實現,
BOOL addSuccess = class_addMethod(self.class, @selector(sendAction:to:forEvent:), method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
if (addSuccess) {
// 沒有實現, 將源方法的實現替換到交換方法的實現
class_replaceMethod(self.class, @selector(customSendAction:to:forEvent:), method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
}else {
// 已經實現, 直接交換方法
method_exchangeImplementations(oriMethod, cusMethod);
}
?
?
?
Runtime應用
關聯對象(Objective-C Associated Objects)給分類增加屬性
方法魔法(Method Swizzling)方法添加和替換和KVO實現
消息轉發(熱更新)解決Bug(JSPatch)
實現NSCoding的自動歸檔和自動解檔
實現字典和模型的自動轉換(MJExtension)
?
?
?
參考:iOS Runtime詳解
參考:深入淺出Runtime (一) 什么是Runtime?
參考:新手也看得懂的 iOS Runtime 教程