iOS進(jìn)階之runtime作用

圖片來源于網(wǎng)絡(luò)

前言

Runtime基本是用C和匯編寫的,可見蘋果為了動態(tài)系統(tǒng)的高效而作出的努力。你可以在這里下到蘋果維護(hù)的開源代碼。蘋果和GNU各自維護(hù)一個開源的runtime版本自阱,這兩個版本之間都在努力的保持一致。Objective-C 從三種不同的層級上與 Runtime 系統(tǒng)進(jìn)行交互米酬,分別是通過 Objective-C 源代碼沛豌,通過 Foundation 框架的NSObject類定義的方法通過對 runtime 函數(shù)的直接調(diào)用赃额。大部分情況下你就只管寫你的Objc代碼就行加派,runtime 系統(tǒng)自動在幕后辛勤勞作著。

1跳芳、概念

RunTime簡稱運(yùn)行時,就是系統(tǒng)在運(yùn)行的時候的一些機(jī)制芍锦,其中最主要的是消息機(jī)制。

??飞盆、ios進(jìn)階之傳遞消息
??
2娄琉、作用

1.動態(tài)交換兩個方法的實現(xiàn)
2.為類別添加屬性(我們知道類別是不能擴(kuò)展屬性的次乓,只能擴(kuò)展方法,但可以運(yùn)行時實現(xiàn)孽水,通過為類增加屬性)
3.獲取某個類的所有成員變量和成員方法
4.實現(xiàn)NSCoding的自動歸檔和自動解檔
5.動態(tài)添加對象的成本變量和成員方法
作用:當(dāng)硬件內(nèi)存過小的時候票腰,如果我們將每個方法都直接加到內(nèi)存當(dāng)中去,但是幾百年不用一次女气,這樣就造成了浪費(fèi)杏慰,所有采取動態(tài)添加
6.實現(xiàn)字典和模型的自動轉(zhuǎn)換

3、詳解:

一主卫、動態(tài)交換方法

1.在自定義類DWExchangeTwoMethod.m中

- (instancetype)init {
    if (self = [super init]) {
        Method workMethod = class_getInstanceMethod([DWExchangeTwoMethod class], @selector(work));
        Method playMethod = class_getClassMethod([DWExchangeTwoMethod class], @selector(play));
        method_exchangeImplementations(workMethod, playMethod);
    }
    return self;
}

- (void)play {
    NSLog(@"玩...");
}

+ (void)work {
    NSLog(@"工作...");
}

拋磚引玉:可以交換方法逃默,防止數(shù)組越界導(dǎo)致的崩潰

2鹃愤、然后在其他類調(diào)用

    DWExchangeTwoMethod *exchangeMethod = [DWExchangeTwoMethod new];
    [exchangeMethod play];

由上可以看出簇搅,調(diào)用的是play方法
但打印結(jié)果為 【玩...】,證明已經(jīng)動態(tài)交換成功

二软吐、為分類添加屬性

一般情況下瘩将,分類不可以添加屬性,但用runtime卻可以實現(xiàn)

- (NSString *)height {
    return objc_getAssociatedObject(self, @"height");
}

- (void)setHeight:(NSString *)height {
    objc_setAssociatedObject(self, @"height", height, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

注:
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
id object :表示關(guān)聯(lián)者凹耙,是一個對象姿现,變量名理所當(dāng)然也是object
const void *key :獲取被關(guān)聯(lián)者的索引key
id value :被關(guān)聯(lián)者,這里是一個block
objc_AssociationPolicy policy : 關(guān)聯(lián)時采用的協(xié)議肖抱,有assign备典,retain,copy等協(xié)議意述,一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC

objc_getAssociatedObject(id object, const void *key)
參數(shù)解析同上

三提佣、獲取實例變量列表
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([DWExchangeTwoMethod class], &outCount);
    for (int i = 0; i < outCount; i++) {
        Ivar ivar = ivars[i];
        const char* name = ivar_getName(ivar);
        const char* type = ivar_getTypeEncoding(ivar);        
        NSLog(@"變量名%s :%s", name, type);
    }
//    此時要注意, 盡管在ARC模式下, 取出變量后要依然手動釋放內(nèi)存, 利用free()方法即可:
    free(ivars);

注:
class_copyPropertyList與class_copyIvarList
class_copyPropertyList返回的僅僅是對象類的屬性(@property申明的屬性),而class_copyIvarList返回類的所有屬性和變量(包括在@interface大括號中聲明的變量)

四荤崇、實現(xiàn)NSCoding的自動歸檔和自動解檔拌屏;

(不用對每個屬性edcode和decode了,如果幾十個屬性一個個的encode和decode真的很麻煩啊,使用運(yùn)行時可以遍歷出每個對象的屬性,數(shù)組的方式遍歷eccode,decode)

#import "DWPerson.h"

#define kname           @"name"
#define kidCard         @"idCard"
#define kage            @"age"
#define kothers         @"others"

@implementation DWPerson

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:_name forKey:kname];
    [aCoder encodeObject:_idCard forKey:kidCard];
    [aCoder encodeInt:_age forKey:kage];
    [aCoder encodeObject:_others forKey:kothers];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        _name = [aDecoder decodeObjectForKey:kname];
        _age = [aDecoder decodeIntForKey:kage];
        _idCard = [aDecoder decodeObjectForKey:kidCard];
        _others = [aDecoder decodeObjectForKey:kothers];
    }
    return self;
}

@end

上面每個類都要寫一次,所以我們添加個分類會更加簡化

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

@implementation NSObject (ArchiveExtension)

// 先對當(dāng)前類進(jìn)行編碼术荤,然后對父類進(jìn)行編碼倚喂,如果父類是NSObject就結(jié)束編碼
- (void)encode:(NSCoder *)aCoder {
    // 一層層父類往上查找,對父類的屬性執(zhí)行歸解檔方法
    Class c = self.class;
    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)];
            id value = [self valueForKey:key];
            [aCoder encodeObject:value forKey:key];
        }
        
        free(ivars);
        c = [c superclass];
    }
}

- (void)decode:(NSCoder *)aDecoder {
    Class c = self.class;
    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)];
            //注意與歸檔的順序不同
            id value = [aDecoder decodeObjectForKey:key];
            [self setValue:value forKey:key];
        }
        free(ivars);
        c = [c superclass];
    }
}

@end

這時瓣戚,可以在DWPerson.m中取代之前的代碼

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [self encode:aCoder];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        [self decode:aDecoder];
    }
    return self;
}

當(dāng)然還可以更加簡潔端圈,把NSCoding的定義成宏

#ifndef Archive_h
#define Archive_h

#import "NSObject+ArchiveExtension.h"


#define ArchiveImplemention \
\
- (instancetype)initWithCoder:(NSCoder *)aDecoder {\
    if (self = [super init]) {\
        [self decode:aDecoder];\
    }\
    return self;\
}\
\
- (void)encodeWithCoder:(NSCoder *)aCoder {\
    [self encode:aCoder];\
}  //最后這句不用斜線
#endif /* Archive_h */

注:
如果有空行,需要加斜線補(bǔ)充

使用:

//宏定義
#import "Archive.h"

@implementation DWPerson

ArchiveImplemention

@end

五子库、動態(tài)添加方法

在viewController使用

- (IBAction)clickBtn:(id)sender {
    
    [self performSelector:@selector(play)];
}

void play(id self, SEL _cmd) {
    NSLog(@"動態(tài)添加成功");
    UIViewController *vc = [UIViewController new];
    vc.view.backgroundColor = [UIColor redColor];
    [self presentViewController:vc animated:YES completion:nil];
}

+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
    if (aSEL ==  NSSelectorFromString(@"play")) {
        class_addMethod(self, aSEL, (IMP) play, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:aSEL];
}

六舱权、實現(xiàn)字典和模型的自動轉(zhuǎn)換

獲取屬性的列表的方法是字典轉(zhuǎn)模型的比較核心的方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刚照,隨后出現(xiàn)的幾起案子刑巧,更是在濱河造成了極大的恐慌喧兄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啊楚,死亡現(xiàn)場離奇詭異吠冤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)恭理,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門拯辙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颜价,你說我怎么就攤上這事涯保。” “怎么了周伦?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵夕春,是天一觀的道長。 經(jīng)常有香客問我专挪,道長及志,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任寨腔,我火速辦了婚禮速侈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迫卢。我一直安慰自己倚搬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布乾蛤。 她就那樣靜靜地躺著每界,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幻捏。 梳的紋絲不亂的頭發(fā)上盆犁,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音篡九,去河邊找鬼谐岁。 笑死,一個胖子當(dāng)著我的面吹牛榛臼,可吹牛的內(nèi)容都是我干的伊佃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼沛善,長吁一口氣:“原來是場噩夢啊……” “哼航揉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起金刁,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤帅涂,失蹤者是張志新(化名)和其女友劉穎议薪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媳友,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斯议,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了醇锚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哼御。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖焊唬,靈堂內(nèi)的尸體忽然破棺而出恋昼,到底是詐尸還是另有隱情,我是刑警寧澤赶促,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布液肌,位于F島的核電站,受9級特大地震影響芳杏,放射性物質(zhì)發(fā)生泄漏矩屁。R本人自食惡果不足惜辟宗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一爵赵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泊脐,春花似錦空幻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至缩挑,卻和暖如春但两,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背供置。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工谨湘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人芥丧。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓紧阔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親续担。 傳聞我的和親對象是個殘疾皇子擅耽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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

  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運(yùn)行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,697評論 7 64
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉物遇,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,682評論 0 9
  • 注:以下圖片素材皆來自于網(wǎng)絡(luò)乖仇。 上周日憾儒,《歡樂喜劇人》第二季拉下了帷幕,小岳岳更是在萬眾矚目與期盼下乃沙,帶著一幫德云...
    娛樂圈老王閱讀 398評論 0 0
  • 曾經(jīng)夢幻過的種種山景特色航夺,溪水湍流、樹木綠蔭崔涂,瀑布銀練阳掐,也許還有更令人嘆為觀止的景色,就這樣一下子夢斷了冷蚂。我是出奇...
    鄧文偉閱讀 983評論 0 0
  • 腦海里浮現(xiàn)出一個畫面蝙茶,在鄉(xiāng)下的柏油路上艺骂,在一輛有些破舊的班車?yán)铮粋€小女孩坐在靠著窗的位置隆夯,望著窗外的風(fēng)景钳恕,發(fā)呆。...
    好魚閱讀 268評論 1 2