runtime的作用及實(shí)例

什么是runtime

runtime是底層的純C語言的API鞠苟,它包含的很多底層的語法乞榨。
我們平時編寫的OC代碼,在程序運(yùn)行過程中当娱,最終都是轉(zhuǎn)化成了runtime的C語言代碼吃既,
runtime也稱為運(yùn)行時,它是OC的幕后工作者跨细。

runtime的作用

runtime主要就是做一些底層的操作鹦倚,如:
   1. 動態(tài)的添加對象的成員變量和方法
   2.動態(tài)交換兩個方法的實(shí)現(xiàn)(可以替換系統(tǒng)的方法)
   3.獲得某個類的所有成員方法、所有成員變量
   4. 實(shí)現(xiàn)分類也可以添加屬性
   5.實(shí)現(xiàn)NSCoding的自動歸檔和解檔
   6.實(shí)現(xiàn)字典轉(zhuǎn)模型的自動轉(zhuǎn)換

替換系統(tǒng)方法冀惭,可以通過攔截系統(tǒng)的方法探究底層震叙,比如block 的實(shí)現(xiàn)原理

常用方法

1.獲取類中的方法

Method class_getClassMethod(Method cls , SEL name)

如:

Method m = class_getClassMethod([Person class],@selector(setName:));

2.獲取對象中的方法

Method class_getInstanceMethod(Method cls, SEL name)

如:

Person *person = [[Person alloc] init];
Method m = get_InstanceMethod([person class],@selector(setName:));

3.交換兩個方法的實(shí)現(xiàn)

 void method_exchangeImplementations(Method m1,Method m2)

     Person *p =[[Person alloc] init];
    [p study];
    [p run];
    //交換實(shí)現(xiàn)
    //instance method :實(shí)例方法掀鹅,
    //class_getInstanceMethod得到實(shí)例的方法(即對象方法)
    //兩個參數(shù) 1:類名 2.方法名
    //class_getClassMethod :得到實(shí)例化的方法
    Method m1 = class_getInstanceMethod([Person class], @selector(study));
    Method m2 = class_getInstanceMethod([Person class], @selector(run));
    method_exchangeImplementations(m2, m1);
    [p study];
    [p run];

具體操作


051B23EE-AFC6-4C95-9297-1E58708D5B96.png

4.獲取成員變量

Ivar  *ivars = class_getCopyIvarList(Ivar ivar);

實(shí)現(xiàn)分類中添加屬性

為所有的NSObject對象添加屬性
1.首先創(chuàng)建一個NSObject分類NSObject+Extension
2.在.h中使用@property添加屬性

此時使用@property添加數(shù)屬性,并非真正的屬性媒楼,如果此時調(diào)用查看屬性乐尊,將會崩潰,
因?yàn)榉诸惒⑽磳?shí)現(xiàn)添加添加屬性的功能划址,想要添加屬性扔嵌,需要使用runtime,動態(tài)的添加

3.在.m文件中實(shí)現(xiàn)getter和setter方法

如果想要添加多個屬性夺颤,就需要在每個對象中抽出一塊空間用于存放屬性痢缎,
使用objc_setAssociatedObject方法進(jìn)行關(guān)聯(lián)

#import "NSObject+Extension.h"
#import <objc/runtime.h>
@implementation NSObject (Extension)
//用于存放屬性的變量,多個屬性世澜,需要創(chuàng)建不同的變量
char BookKey;
-(void)setBooks:(NSArray *)books{
objc_setAssociatedObject(self, &BookKey, books, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSArray *)books{
return objc_getAssociatedObject(self, &BookKey);
}
@end

遵守協(xié)議NSCoding独旷,實(shí)現(xiàn)屬性的自動歸檔與解檔

需求分析:
當(dāng)想要對象自動進(jìn)行歸檔解檔的時候,如果屬性非常的多寥裂,一個一個天添加[encoder encodeObject:@(xxx) forKey:@"_xxx"];將會非常的繁瑣势告。
既然能夠獲取所有的屬性,我們就可以通過循環(huán)遍歷屬性的方式進(jìn)行統(tǒng)一的歸檔和解檔

- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init]) {
    // 用來存儲成員變量的數(shù)量
    unsigned int outCount = 0;
    
    // 獲得Dog類的所有成員變量
    Ivar *ivars = class_copyIvarList([self class], &outCount);
    
    // 遍歷所有的成員變量
    for (int i = 0; i<outCount; i++) {
        // 取出i位置對應(yīng)的成員變量
        Ivar ivar = ivars[i];
        
        NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
        // 獲得key對應(yīng)的值
        id value = [decoder decodeObjectForKey:key];
        
        // 設(shè)置到成員變量上
        [self setValue:value forKeyPath:key];
    }
    
    free(ivars);
}
return self;
}

/**
 * 將對象寫入文件時會調(diào)用這個方法(開發(fā)者需要在這個方法中說明需要存儲哪些屬性)
 */
- (void)encodeWithCoder:(NSCoder *)encoder
{
// 用來存儲成員變量的數(shù)量
unsigned int outCount = 0;

// 獲得Dog類的所有成員變量
Ivar *ivars = class_copyIvarList([self class], &outCount);

// 遍歷所有的成員變量
for (int i = 0; i<outCount; i++) {
    // 取出i位置對應(yīng)的成員變量
    Ivar ivar = ivars[i];
    
    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
    // 通過key獲得對應(yīng)成員變量的值
    id value = [self valueForKeyPath:key];
    
    [encoder encodeObject:value forKey:key];
}

free(ivars);
}

注意:

ARC的內(nèi)存管理機(jī)制 只適合OC語法抚恒,對于C語言的內(nèi)存還是需要手動的釋放,當(dāng)使用runtime的時候络拌,
如果包含了copy俭驮、create、retain春贸、new等詞語混萝,那么在最后就需要釋放內(nèi)存

使用free(對象)進(jìn)行釋放如:free(ivars);

利用runtime實(shí)現(xiàn)字典轉(zhuǎn)模型

描述:

KVC的字典轉(zhuǎn)模型具有一個缺陷,就是屬性的數(shù)量與名稱都必須保持一致萍恕,如果字典中的屬性多逸嘀,
而模型中沒有使用KVC賦值的時候就會崩潰,需要實(shí)現(xiàn)另一個方法 
setValue:forUndefinedKey:方法允粤,并如果對象中包含了另一個對象作為屬性崭倘,
也將不能自動將其轉(zhuǎn)化為模型

而使用runtime實(shí)現(xiàn)的字典轉(zhuǎn)模型,可以實(shí)現(xiàn)將所有的對象都轉(zhuǎn)化為對應(yīng)的模型类垫,
并且不會出現(xiàn)屬性找不到司光,而奔潰的現(xiàn)象

NSObject+Extension.h
#import <Foundation/Foundation.h>
@interface NSObject (Extension)
-(void)setDiction:(NSDictionary *)dict;
+(instancetype)objectWithDiction:(NSDictionary *)dict;
@end

NSObject+Extension.m

#import "NSObject+Extension.h"
#import <objc/runtime.h>

@implementation NSObject (Extension)

-(void)setDiction:(NSDictionary *)dict{
//獲取類
Class c = self.class;
//循環(huán)遍歷 類 (本類 和所有的父類)
while (c && c != [NSObject class]) {
    //獲取所有的屬性
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList(c, &outCount);
    //遍歷類中的屬性
    for (int i = 0; i < outCount; i++) {
        //獲取屬性名
        Ivar ivar = ivars[i];
        NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
        //去掉key中的 _
        key = [key substringFromIndex:1];
        //通過key 獲取屬性的值
        id value = dict[key];
        //如果key是一個空值 退出本輪的循環(huán)
        //原因:如果字典中沒有這個key,那么value將會是一個空值悉患,kvc 不能賦值空值
        if (value == nil) {
            continue;
        }
        //如果類中包含另一個類為對象残家,也要將該對象進(jìn)行字典轉(zhuǎn)模型
        //獲取對象的屬性的類名
        NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        // 對象名會以@“名字”的形式 出現(xiàn),但是同時字符串也是以這種形式表示售躁,因此可以先判斷type中是否包含 @ 符號
        NSRange range = [type rangeOfString:@"@"];
        //如果range.location 不等于NSNotFound說明 找到了@
        if (range.location != NSNotFound) {
            //截取type中的名字 去除@“ ”
            type = [type substringWithRange:NSMakeRange(2, type.length -3)];
            if (![type hasPrefix:@"NS"]) {
                //將type轉(zhuǎn)化為類名
                Class class = NSClassFromString(type);
                value = [class objectWithDiction:value];
            }
            
        }
        
        //賦值
        [self setValue:value forKey:key];
        
    }
    //ARC 只適用于OC語法坞淮,C語言中的內(nèi)存 需要手動釋放
    free(ivars);
    c = [c superclass];
    NSLog(@"1");
  }
}
+(instancetype)objectWithDiction:(NSDictionary *)dict{
NSObject *obj = [[self alloc] init];
[obj setDiction:dict];
return  obj;
}  
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茴晋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子回窘,更是在濱河造成了極大的恐慌诺擅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毫玖,死亡現(xiàn)場離奇詭異掀虎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)付枫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門烹玉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阐滩,你說我怎么就攤上這事二打。” “怎么了掂榔?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵继效,是天一觀的道長。 經(jīng)常有香客問我装获,道長瑞信,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任穴豫,我火速辦了婚禮凡简,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘精肃。我一直安慰自己秤涩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布司抱。 她就那樣靜靜地躺著筐眷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪习柠。 梳的紋絲不亂的頭發(fā)上匀谣,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音资溃,去河邊找鬼振定。 笑死,一個胖子當(dāng)著我的面吹牛肉拓,可吹牛的內(nèi)容都是我干的后频。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼卑惜!你這毒婦竟也來了膏执?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤露久,失蹤者是張志新(化名)和其女友劉穎更米,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毫痕,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡征峦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了消请。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栏笆。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖臊泰,靈堂內(nèi)的尸體忽然破棺而出蛉加,到底是詐尸還是另有隱情,我是刑警寧澤缸逃,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布针饥,位于F島的核電站,受9級特大地震影響需频,放射性物質(zhì)發(fā)生泄漏丁眼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一昭殉、第九天 我趴在偏房一處隱蔽的房頂上張望苞七。 院中可真熱鬧,春花似錦饲化、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至足淆,卻和暖如春巢块,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巧号。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工族奢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丹鸿。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓越走,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子廊敌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容