1.runtime實(shí)現(xiàn)的機(jī)制是什么,怎么用闰集,一般用于干嘛沽讹?
runtime是一套比較底層的純C語(yǔ)言API, 屬于1個(gè)C語(yǔ)言庫(kù), 包含了很多底層的C語(yǔ)言API。 runtime庫(kù)里
面包含了跟類武鲁、成員變量爽雄、方法相關(guān)的API,比如獲取類里面的所有成員變量,為類動(dòng)態(tài)添 加成員變量,動(dòng)態(tài)改變
類的方法實(shí)現(xiàn),為類動(dòng)態(tài)添加新的方法等 需要導(dǎo)入<objc/message.h><objc/runtime.h>
在我們平時(shí)編寫的OC代碼中, 程序運(yùn)行過(guò)程時(shí), 其實(shí)最終都是轉(zhuǎn)成了runtime的C語(yǔ)言代碼,比如類轉(zhuǎn)成了
runtime庫(kù)里面的結(jié)構(gòu)體等數(shù)據(jù)類型,方法轉(zhuǎn)成了runtime庫(kù)里面的C語(yǔ)言函數(shù),平時(shí)調(diào)方法都是轉(zhuǎn)成了objc_msgSend
函數(shù)(所以說(shuō)OC有個(gè)消息發(fā)送機(jī)制)因此,可以說(shuō)runtime是OC的底層實(shí)現(xiàn),是OC的幕后執(zhí)行者有了runtime庫(kù),
能做什么事情呢?runtime庫(kù)里面包含了跟類、成員變量沐鼠、方法相關(guān)的API,runtime是屬于OC的底層, 可以進(jìn)
行一些非常底層的操作(用OC是無(wú)法現(xiàn)實(shí)的, 不好實(shí)現(xiàn))
1.在程序運(yùn)行過(guò)程中, 動(dòng)態(tài)創(chuàng)建一個(gè)類(比如KVO的底層實(shí)現(xiàn))
2.在程序運(yùn)行過(guò)程中, 動(dòng)態(tài)地為某個(gè)類添加屬性\方法, 修改屬性值\方法
3.遍歷一個(gè)類的所有成員變量(屬性)\所有方法
有了runtime,想怎么改就怎么改, runtime算是OC的幕后工作者.
對(duì)于上面提到的KVO內(nèi)部實(shí)現(xiàn)原理:
? KVO是基于runtime機(jī)制實(shí)現(xiàn)的
? 當(dāng)某個(gè)類的對(duì)象第一次被觀察時(shí),系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類的一個(gè)派生類,在這個(gè)派生類中重寫基
類中任何被觀察屬性的setter 方法,并且在setAge方法里然后用監(jiān)聽(tīng)者的observeValueForKeyPath...
把對(duì)應(yīng)的值傳出去通知監(jiān)聽(tīng)者發(fā)生了事情.
派生類在被重寫的 setter 方法實(shí)現(xiàn)真正的通知機(jī)制(Person -> NSKVONotifying_Person)
具體應(yīng)用:
當(dāng)我們需要對(duì)一個(gè)類的屬性進(jìn)行歸檔解檔的時(shí)候?qū)傩蕴貏e的多挚瘟,這時(shí)候叹谁,我們就會(huì)寫很多對(duì)應(yīng)的代碼,但是如果使用了runtime就可以動(dòng)態(tài)設(shè)置乘盖!
例如焰檩,Person.h的文件如下所示
@interface Person : NSObject
@property (nonatomic, assign) int age;
@property (nonatomic, assign) int height;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age2;
@property (nonatomic, assign) int height2;
@property (nonatomic, assign) int age3;
@property (nonatomic, assign) int height3;
@property (nonatomic, assign) int age4;
@property (nonatomic, assign) int height4;
@end
而Person.m實(shí)現(xiàn)文件的內(nèi)容如下
@implementation Person
(void)encodeWithCoder:(NSCoder )encoder
{
unsigned int count = 0;
Ivar ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i<count; i++) {
// 取出i位置對(duì)應(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([PYPerson class], &count);
for (int i = 0; i<count; i++) {
// 取出i位置對(duì)應(yīng)的成員變量
Ivar ivar = ivars[i];
// 查看成員變量
const char *name = ivar_getName(ivar);
// 解檔
NSString *key = [NSString stringWithUTF8String:name];
id value = [decoder decodeObjectForKey:key];
// 設(shè)置到成員變量身上
[self setValue:value forKey:key];
}
free(ivars);
}
return self;
}
@end
這樣我們可以看到歸檔和解檔的案例其實(shí)是runtime寫下的,學(xué)習(xí)runtime機(jī)制首先要了解下面幾個(gè)問(wèn)題
1相關(guān)的頭文件和函數(shù)
1> 頭文件
利用頭文件,我們可以查看到runtime中的各個(gè)方法订框!
2> 相關(guān)應(yīng)用
NSCoding(歸檔和解檔, 利用runtime遍歷模型對(duì)象的所有屬性)
字典 –> 模型 (利用runtime遍歷模型對(duì)象的所有屬性, 根據(jù)屬性名從字典中取出對(duì)應(yīng)的值, 設(shè)置到模型的屬性上)
KVO(利用runtime動(dòng)態(tài)產(chǎn)生一個(gè)類)
用于封裝框架(想怎么改就怎么改)
這就是我們r(jià)untime機(jī)制的只要運(yùn)用方向
3> 相關(guān)函數(shù)
objc_msgSend : 給對(duì)象發(fā)送消息
class_copyMethodList : 遍歷某個(gè)類所有的方法
class_copyIvarList : 遍歷某個(gè)類所有的成員變量
class_…..
這是我們學(xué)習(xí)runtime必須知道的函數(shù)析苫!
4.必備常識(shí)
1> Ivar : 成員變量
2> Method : 成員方法
從上面例子中我們看到我們定義的成員變量,如果要是動(dòng)態(tài)創(chuàng)建方法穿扳,可以使用Method