1.對runtime的理解
- runtime是系統(tǒng)在運行的時候的一些機制,其中最主要的是消息機制。
- OC從三種不同的層級上與runtime進(jìn)行交互,分別是通過OC源碼,通過Foundation框架的NSObject類定義的方法,通過對runtime函數(shù)的直接調(diào)用。大部分情下runtime自動在幕后工作。
- 對于C語言,函數(shù)的調(diào)用在編譯的時候會決定調(diào)用哪個函數(shù),編譯完成之后直接順序執(zhí)行,無任何二義性。
- OC的函數(shù)調(diào)用成為消息發(fā)送。屬于動態(tài)調(diào)用過程。在編譯的時候并不能決定真正調(diào)用哪個函數(shù)(事實證明,在編譯階段,OC可以調(diào)用任何函數(shù),即使這個函數(shù)并未實現(xiàn),只要申明過就不會報錯。而C語言在編譯階段就會報錯)。
2. runtime的使用
- 1.將某些OC代碼轉(zhuǎn)為運行時代碼,探究底層。
- 2.攔截系統(tǒng)自帶的方法調(diào)用,也可以說成對系統(tǒng)的方法進(jìn)行替換,比如攔截imageNamed:、viewDidLoad、alloc;例如:
- a、為UIImage建一個分類(UIImage+Category),實現(xiàn)一個自定義方法
+ (UIImage *)customImageNamed:(NSString *)name {
doubleversion = [[UIDevicecurrentDevice].systemVersiondoubleValue];
if(version >=8.0) {
// 如果系統(tǒng)版本是8.0以上,使用另外一套文件名結(jié)尾是‘_os7’的扁平化圖片
name = [name stringByAppendingString:@"_os7"];
}
return[UIImagecustomNamed:name];
}
- b、分類中重寫UIImage的load方法,實現(xiàn)方法的交換
+ (void) load {
// 獲取兩個類的類方法
Method m1 = class_getClassMethod([UIImageClass],@selector(imageNamed:));
Method m2 = class_getClassMethod([UIImageClass],@selector(customImageNamed:));
method_exchangeImplementations(m1, m2);
}
>注意:自定義方法中最后一定要再調(diào)用一下系統(tǒng)的方法,讓其有加載圖片的功能,但是由于方法交換,系統(tǒng)的方法名已經(jīng)變成了我們自定義的方法名(有點繞,就是用我們的名字能調(diào)用系統(tǒng)的方法,用系統(tǒng)的名字能調(diào)用我們的方法),這就實現(xiàn)了系統(tǒng)方法的攔截!
- 3.實現(xiàn)分類也可以增加屬性。
- 4.實現(xiàn)NSCoding的自動歸檔和自動解檔;(不用對每個屬性edcode和decode了,使用運行時可以遍歷出每個對象的屬性,數(shù)組的方式遍歷eccode,decode)
- 用運行時的歸檔方法
- (void) encodeWithCoder: (NSCoder *) encoder {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i++) {
// 取出i位置對應(yīng)的成員變量
Ivar ivar = ivars[i];
// 查看成員變量
const char *name = ivar_getName(ivar);
// 歸檔
NSString *key = [NSString stringWithUTF8String:name];
id value = [self valueForKey:key];
[encoder encodeObject: value forKey:key];
}
free(ivars);
}
- 用運行時的解歸檔方法
- (id) initWithCoder: (NSCoder *) decoder {
if (self = [super init]) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i++) {
// 取出i位置對應(yīng)的成員變量
Ivar ivar = ivars[i];
// 查看成員變量
const char *name = ivar_getName(ivar);
// 歸檔
NSString *key = [NSString stringWithUTF8String:name];
id value = [self valueForKey:key];
[encoder encodeObject: value forKey:key];
}
free(ivars);
}
return self;
}
- 5.實現(xiàn)字典和模型的自動轉(zhuǎn)換(核心就是可以遍歷出字典中的每個屬性,json解析中大牛框架都用了這個特性,包括MJEXtension,YYModel,jsonModel都是將json轉(zhuǎn)換為字典,再遍歷字典中的每個屬性來進(jìn)行modle的轉(zhuǎn)換)。
- 經(jīng)查看源碼發(fā)現(xiàn)獲取屬性的列表的方法是字典轉(zhuǎn)模型的比較核心方法:
OBJC_EXPORT Ivar *class_copyIvarList(Class cos, unsigned int *outCount)
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
結(jié)論: 使用運行時動態(tài)獲取屬性的屬性名的方法,來進(jìn)行字典轉(zhuǎn)模型替換,字典轉(zhuǎn)模型效率最高的(耗時最短的)的是KVC,其他的字典轉(zhuǎn)模型是在KVC 的key 和Value 做處理,動態(tài)的獲取json 中的key 和value
- 經(jīng)查看源碼發(fā)現(xiàn)獲取屬性的列表的方法是字典轉(zhuǎn)模型的比較核心方法: