1. 概述
OC 是一個全動態語言,OC 的一切都是基於 Runtime 實現的
只有在程序運行時,纔會去確定對象的類型,並調用類與對象相應的方法`
2. 運行時機制
運行時機制是用 C++ 開發的,是一套蘋果開源的框架
OC 是基於運行時開發的語言
3. 應用場景
運行時動態獲取類的屬性
主要應用:
- 字典轉模型框架 MJExtension,JSONModel
- 利用
關聯對象
爲分類添加屬性 - 利用
交換方法
攔截系統或其他框架的方法 - 誤區:並不是使用的技術越底層,框架的效率就會越高
導入頭文件
#import <objc/runtime.h>
4. 示例
爲NSObject添加一個分類
//
// NSObject+Extension.m
//
#import "NSObject+Extension.h"
#import <objc/runtime.h>
@implementation NSObject (Extension)
const char *propertiesKey = "propertiesKey";
const char *methodsKey = "methodsKey";
const char *protocolKey = "protocolKey";
/// 字典轉模型方法
+ (instancetype)objectWithDict:(NSDictionary *)dict
{
id obj = [[self alloc] init];
// 獲取屬性列表
NSArray *properties = [self propertyList];
// 遍歷屬性數組
for (NSString *key in properties)
{
// 判斷字典中是否包含這個key
if (dict[key] != nil)
{
// 使用 KVC 設置屬性值
[obj setValue:dict[key] forKeyPath:key];
}
}
return obj;
}
/**
如果能夠自動生成這個數組,就好了!
如果要想動態的獲取類的屬性,需要使用到“運行時機制”
class_copyIvarList 成員變量,提示有很多第三方框架會使用 Ivar,能夠獲得更多的信息
但是:在 swift 中,由於語法結構的變化,使用 Ivar 非常不穩定,經常會崩潰!
class_copyPropertyList 屬性
class_copyMethodList 方法
class_copyProtocolList 協議
*/
/// 返回類的屬性列表
+ (NSArray *)propertyList
{
// 0. 判斷是否存在關聯對象, 如果存在, 直接返回
/** 參數
1> 關聯到得對象
2> 關聯的屬性 key
*/
NSArray *plist = objc_getAssociatedObject(self, propertiesKey);
if (plist)
{
return plist;
}
// 1. 獲取 '類的屬性'
/**
1> 類
2> 屬性的計數指針
*/
unsigned int count = 0;
// 返回值是所有屬性的數組 obj_property_
objc_property_t *list = class_copyPropertyList([self class], &count);
// 創建 存儲屬性數組
NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count; ++i)
{
// 獲取屬性
objc_property_t pty = list[i];
// 獲取屬性名
const char *cname = property_getName(pty);
[arrayM addObject:[NSString stringWithUTF8String:cname]];
}
// 釋放屬性數組
free(list);
// 設置關聯對象
/**
1> 關聯的對象
2> 關聯對象的 key
3> 屬性數值
4> 屬性的持有方式 reatin, copy, assign
*/
objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
return arrayM.copy;
}
/// 返回類的方法列表
+ (NSArray *)methodList
{
// 0. 判斷是否存在依賴關係
NSArray *mlist = objc_getAssociatedObject(self, methodsKey);
if (mlist)
{
return mlist;
}
unsigned int count = 0;
// 1. 獲取方法列表
Method *list = class_copyMethodList([self class], &count);
// 存儲方法數組
NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count; ++i)
{
// 獲取方法
Method method = list[i];
// 獲取方法名
SEL mname = method_getName(method);
[arrayM addObject: NSStringFromSelector(mname)];
}
// 釋放數組
free(list);
// 設置依賴關係
objc_setAssociatedObject(self, methodsKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
return arrayM.copy;
}
/// 返回類的實現協議列表
+ (NSArray *)protocolList
{
// 0. 判斷是否存在依賴關係
NSArray *pList = objc_getAssociatedObject(self, protocolKey);
if (pList)
{
return pList;
}
unsigned int count = 0;
// 2. 獲取協議列表
Protocol * __unsafe_unretained *list = class_copyProtocolList([self class], &count);
// 創建協議數組
NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count; ++i)
{
// 獲取協議
Protocol * __unsafe_unretained prot = list[i];
const char *pname = protocol_getName(prot);
[arrayM addObject:[NSString stringWithUTF8String:pname]];
}
return arrayM;
}
@end