iOS Runtime的理解與使用

簡介

Objective-C是一門古老的語言煎饼,但是是一門動態(tài)性的語言,因?yàn)樗膭討B(tài)性趴泌,使其又有了強(qiáng)大的生命力告组,在蘋果生態(tài)系統(tǒng)的平臺應(yīng)用廣泛,可謂互相成全了對方煤伟,Objective-C的動態(tài)性隨處可見,當(dāng)子類覆寫父類方法的時候木缝,總是在執(zhí)行前才決定該執(zhí)行什么便锨,不像C在編譯時就已經(jīng)決定了代碼的執(zhí)行,能讓Objective-C有強(qiáng)大動態(tài)性的就是Runtime類庫我碟。

原理

Runtime的核心就是消息轉(zhuǎn)發(fā)放案,當(dāng)對象調(diào)用方法是,程序執(zhí)行[object doSomething]時矫俺,會向消息接收者(object)發(fā)送一條消息(doSomething)吱殉,runtime會根據(jù)消息接收者是否能響應(yīng)該消息而做出不同的反應(yīng)。
簡單的說主要有這幾點(diǎn):
1.消息傳遞(Messaging)
2.動態(tài)方法解析和轉(zhuǎn)發(fā)
原理這一塊兒我并沒有寫的很詳細(xì)厘托,大家可以看這幾篇原理博客的詳細(xì)介紹友雳。

使用

1.在使用delegate的時候我們在判斷代理是否遵守協(xié)議的時候,會發(fā)送一條消息,當(dāng)消息沒有被響應(yīng)的時候铅匹,會拋出異常押赊。

  //這里就是發(fā)送了一條消息,看代理是否能夠響應(yīng)到伊群,響應(yīng)到的時候執(zhí)行方法
    if ([self.delegate respondsToSelector:@selector(dosomething:)]) {
        [self.delegate dosomething:@""];
    }

2.給對象添加category的時候是沒有辦法給之間添加property方法的考杉,需要使用runtime進(jìn)行動態(tài)綁定,這個可以參考AFNetwortking里面的寫法

@interface UIView (category)
//聲明
@property (nonatomic,copy) NSString *text;

@end
#import "UIView+category.h"
#import <objc/runtime.h>
//設(shè)置key
static char textKey;

@implementation UIView (category)

//設(shè)置關(guān)聯(lián)
-(void)setText:(NSString *)text{
    objc_setAssociatedObject(self, &textKey, text, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

//獲取關(guān)聯(lián)的值
-(NSString *)text{
    return objc_getAssociatedObject(self, &textKey);
}

@end

3.Method Swizzling
我覺得這才是Runtime運(yùn)用場景最為廣泛的地方,java有反射機(jī)制舰始,可以設(shè)置動態(tài)代理,實(shí)現(xiàn)AOP編程咽袜,但是Objective-C的Runtime則更為強(qiáng)大丸卷。


原理圖

下面來看一段代碼

void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) { 
//原始方法指針
 originalMethod = class_getInstanceMethod(class, originalSelector); 
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
 // 給類添加方法指針
didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
 if (didAddMethod)
{
//將原始的方法實(shí)現(xiàn)賦給swizzledSelector
 class_replaceMethod(class, swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
 } else { 
//交換方法實(shí)現(xiàn)
method_exchangeImplementations(originalMethod, swizzledMethod); 
}
}

上面是一段比較常見的方法交叉代碼,但是我們在開發(fā)中用的是Aspects這個第三方的開源庫,用這個開源庫你可以實(shí)現(xiàn)自己的一些埋點(diǎn)統(tǒng)計或者判斷UI刷新询刹。
埋點(diǎn)統(tǒng)計

+ (void)load
{
   
    [UIViewController aspect_hookSelector:@selector(viewWillAppear:)
                              withOptions:AspectPositionAfter
                               usingBlock:^(id<AspectInfo> aspectInfo) {
                                   NSString *className = NSStringFromClass([[aspectInfo instance] class]);
                                   DebugLog(@"%@ class tpo appear",className);
                                   } error:NULL];
    
    [UIViewController aspect_hookSelector:@selector(viewWillDisappear:)
                              withOptions:AspectPositionAfter
                               usingBlock:^(id<AspectInfo> aspectInfo) {
                                   NSString *className = NSStringFromClass([[aspectInfo instance] class]);
                                   DebugLog(@"%@ class tpo disappear",className);
                               } error:NULL];
    
}

判斷子線程UI刷新

+(void)load{
#if DEBUG
    [UIView aspect_hookSelector:@selector(setNeedsLayout)
                    withOptions:AspectPositionAfter
                     usingBlock:^(id<AspectInfo> aspectInfo) {
                         NSString *className = NSStringFromClass([[aspectInfo instance] class]);
                         className = [NSString stringWithFormat:@"%@ can't use in background",className];
                         NSAssert([NSThread isMainThread],className);
                     } error:NULL];
    
    [UIView aspect_hookSelector:@selector(setNeedsDisplay)
                    withOptions:AspectPositionAfter
                     usingBlock:^(id<AspectInfo> aspectInfo) {
                         NSString *className = NSStringFromClass([[aspectInfo instance] class]);
                         className = [NSString stringWithFormat:@"%@ can't use in background",className];
                         NSAssert([NSThread isMainThread],className);
                     } error:NULL];
    [UIView aspect_hookSelector:@selector(setNeedsDisplayInRect:)
                    withOptions:AspectPositionAfter
                     usingBlock:^(id<AspectInfo> aspectInfo) {
                         NSString *className = NSStringFromClass([[aspectInfo instance] class]);
                         className = [NSString stringWithFormat:@"%@ can't use in background",className];
                         NSAssert([NSThread isMainThread],className);
                     } error:NULL];
#else
    //不在release的時候添加是因?yàn)楹蚸spatch有沖突
#endif
}

hotfix
其實(shí)熱修復(fù)有很多方案,原理都是Method Swizzling,比較常見的選擇方案是JSPatch,但是我覺得JSPatch和Aspects沖突引發(fā)崩潰的問題應(yīng)該有JSPatch的作者bang來解決谜嫉,不應(yīng)該由開發(fā)者自己解決,雖然bang團(tuán)隊(duì)給出過解決方案凹联。

愛生活沐兰,愛運(yùn)動,熱愛交流蔽挠,歡迎討論住闯!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子比原,更是在濱河造成了極大的恐慌插佛,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件量窘,死亡現(xiàn)場離奇詭異雇寇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚌铜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門锨侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冬殃,你說我怎么就攤上這事识腿。” “怎么了造壮?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵渡讼,是天一觀的道長。 經(jīng)常有香客問我耳璧,道長成箫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任旨枯,我火速辦了婚禮蹬昌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攀隔。我一直安慰自己皂贩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布昆汹。 她就那樣靜靜地躺著明刷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪满粗。 梳的紋絲不亂的頭發(fā)上辈末,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音映皆,去河邊找鬼挤聘。 笑死,一個胖子當(dāng)著我的面吹牛捅彻,可吹牛的內(nèi)容都是我干的组去。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼步淹,長吁一口氣:“原來是場噩夢啊……” “哼从隆!你這毒婦竟也來了诚撵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤广料,失蹤者是張志新(化名)和其女友劉穎砾脑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艾杏,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韧衣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了购桑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畅铭。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖勃蜘,靈堂內(nèi)的尸體忽然破棺而出硕噩,到底是詐尸還是另有隱情,我是刑警寧澤缭贡,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布炉擅,位于F島的核電站,受9級特大地震影響阳惹,放射性物質(zhì)發(fā)生泄漏谍失。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一莹汤、第九天 我趴在偏房一處隱蔽的房頂上張望快鱼。 院中可真熱鬧,春花似錦纲岭、人聲如沸抹竹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窃判。三九已至,卻和暖如春沽翔,著一層夾襖步出監(jiān)牢的瞬間兢孝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工仅偎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雳殊。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓橘沥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夯秃。 傳聞我的和親對象是個殘疾皇子座咆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

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