智勇博客:
最近比較有空非洲,在這里分享一下OC的底層runtime進(jìn)行時(shí)的一些簡單運(yùn)用,比較適合初學(xué)者來學(xué)習(xí)了解一下。
先說幾句干貨,讓大家了解一些 什么叫做runtime進(jìn)行時(shí)钾怔。
OC語言分4個(gè)階段:
1.編寫程序階段凝垛,也就是大家每天都在做的桃焕。
2.編譯階段
3.鏈接階段
4.運(yùn)行階段而账,也就是runtime進(jìn)行時(shí)
OC雖然在編譯時(shí),會(huì)進(jìn)行一次代碼檢測。但這緊緊只是檢查一些簡單的操作牍颈,比如有沒有寫錯(cuò)什么關(guān)鍵字 哪里的語法有沒有寫錯(cuò),打個(gè)比喻就是像個(gè)老師檢查學(xué)生的作文中有沒有錯(cuò)別字和病句一樣徒爹。如果有錯(cuò)誤就會(huì)有errors或者warning信息提示出來,那都是編譯器檢查出來的泡躯。
進(jìn)行時(shí)就是代碼跑起來惰拱,被裝載到內(nèi)存中去了披泪。而進(jìn)行時(shí)類型檢查就與前面講的編譯時(shí)類型檢查不一樣。不是簡單的掃描代碼。而是在內(nèi)存中做些操作雏吭,做些判斷婚温。如果出現(xiàn)問題則直接崩潰掺逼。
這篇文章主要的是介紹runtime的入門級(jí)運(yùn)用,下面來下實(shí)際點(diǎn)的。
runtime的使用場景其實(shí)可以有很多辕漂,只不過大家平常寫代碼時(shí)并沒有往這方面去想,自然就運(yùn)用不上runtime了
比如需求是:
我們執(zhí)行兩段不一樣的代碼跋涣,但是執(zhí)行的方法名字需要一樣遣臼。某個(gè)時(shí)候調(diào)用這個(gè)方法 是執(zhí)行代碼段1 某個(gè)時(shí)候調(diào)用這個(gè)方法 就是執(zhí)行代碼段2之碗。
還有一個(gè)就是:
在一個(gè)完整的項(xiàng)目中,突然項(xiàng)目經(jīng)理需要修改一個(gè)HUD彈框顯示的背景顏色和文字祭往。而這個(gè)HUD又在整個(gè)項(xiàng)目中的無數(shù)個(gè)地方使用過。那么此時(shí)有一個(gè)很苦力很low的方法栏妖,就是整個(gè)項(xiàng)目中逐一修改乱豆。
還有很多案例等,我就不一一舉例了吊趾。
這些時(shí)候 其實(shí)都是可以用runtime來解決宛裕,就是幾句代碼的事而已。
下面介紹2個(gè)runtime中的方法:
method_exchangeImplementations 來交換2個(gè)方法中的IMP论泛,
method_setImplementation 來直接設(shè)置某個(gè)方法的IMP
IMP可能某些同學(xué)會(huì)比較陌生一點(diǎn)揩尸,起始IMP可以看做為一個(gè)指針存儲(chǔ)器,OC中屁奏,調(diào)用某個(gè)函數(shù)岩榆,轉(zhuǎn)換為C語言就是調(diào)用這個(gè)IMP指向的函數(shù) 說白一點(diǎn),就是通過IMP來找到需要調(diào)用的函數(shù)!
理解了IMP 那么需要偷龍轉(zhuǎn)鳳 就簡單多了勇边。只要把函數(shù)的IMP偷偷轉(zhuǎn)換掉犹撒,到時(shí)候系統(tǒng)調(diào)用的該函數(shù)的時(shí)候,其實(shí)就是調(diào)用了我們新傳進(jìn)去的IMP指向的函數(shù)了粒褒。
這里主要介紹一下method_exchangeImplementations 這個(gè)運(yùn)行時(shí)方法识颊,其他方法之后會(huì)陸續(xù)再寫另一篇文章來跟大家繼續(xù)講解。
下面直接上一段代碼:
+(void)load {
//創(chuàng)建一個(gè)類型 也可以直接寫成 [NSArray class]
Class targetClass = [NSClassFromString(@"NSArray") class];
//返回一個(gè)指定的函數(shù) 這個(gè)函數(shù)指向 [self override_lastObject] 這個(gè)函數(shù)
Method m1 = class_getInstanceMethod([self class], @selector(override_firstObject));
/**
* 給一個(gè)指定的類新增一個(gè)函數(shù)方法
*
* targetClass 需要新增函數(shù)的類
* override_lastObject 新增函數(shù)的名字
* imp 新增函數(shù)調(diào)用時(shí) 指向的地址
* char *types 字符串描述這個(gè)函數(shù)的參數(shù)和返回類型
*
*
* 返回BOOL值
*/
BOOL isbool = class_addMethod(targetClass, @selector(override_firstObject), method_getImplementation(m1), method_getTypeEncoding(m1));
if (isbool == YES) {
NSLog(@"添加方法成功");
} else {
NSLog(@"添加方法失敗");
}
//提取這個(gè)類targetClass 的這個(gè)override_firstObject函數(shù)方法
Method m2 = class_getInstanceMethod(targetClass, @selector(override_firstObject));
//提取這個(gè)類targetClass 的這個(gè)firstObject函數(shù)方法
Method m3 = class_getInstanceMethod(targetClass, @selector(firstObject));
//將兩個(gè)函數(shù)的Imp指向?qū)ο?對(duì)換
method_exchangeImplementations(m2, m3);
}
上面的代碼中 直接在+load方法中實(shí)現(xiàn) 整個(gè)程序運(yùn)行的時(shí)候把代碼噻進(jìn)內(nèi)存中的時(shí)候就會(huì)調(diào)用一次奕坟。也就是程序剛開始運(yùn)行的時(shí)候 我們就已經(jīng)把需要調(diào)換的方法 成功的調(diào)換了
之后只要有NSArray調(diào)用firstObject這個(gè)方法的時(shí)候
就會(huì)調(diào)用了我們自己新寫的方法override_firstObject祥款。
相反也是,只要調(diào)用NSArray的override_firstObject方法時(shí)
就會(huì)調(diào)用原來的firstObject方法了月杉。
需要注意的是 因?yàn)槲覀冊摰氖钦麄€(gè)NSArray類镰踏,所以會(huì)影響到整個(gè)程序的,并不是只影響這個(gè)控制器 或者 這個(gè)頁面的哦沙合!所以使用的時(shí)候需要注意奠伪,別亂該系統(tǒng)級(jí)別的控件!
一下代碼是測試上面的方法 是否成功的:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *array = @[@"1", @"2"];
NSString *str = [array firstObject];
NSLog(@"str = %@",str);
}
-(void)override_firstObject {
NSLog(@"調(diào)用自己新寫的firstObject方法");
[self override_firstObject];
}
上面看起來override_firstObject方法中 好像是一個(gè)遞歸死循環(huán)了首懈,但其實(shí)不是绊率,上面也說過了,override_firstObject 和 firstObject 兩個(gè)方法是做了Imp調(diào)換的究履。所以不會(huì)造成遞歸滤否。
這里的控制臺(tái)輸出順序是:
2017-02-16 16:46:54.917 textDemo[4183:192569] 添加方法成功
2017-02-16 16:46:54.997 textDemo[4183:192569] 調(diào)用自己新寫的lastObject方法
2017-02-16 16:46:54.998 texDemo[4183:192569] str = 1
控制臺(tái)這樣的輸出 已經(jīng)證明了我們將兩個(gè)方法的Imp對(duì)換是成功的。
上面只是為了簡化代碼 所以隨便寫來證實(shí)method_exchangeImplementations方法的運(yùn)用最仑。
只要掌握了runtime的運(yùn)用藐俺,在以后的敲代碼過程中 會(huì)有一個(gè)很大的幫助,能幫助大家走少很多彎路的喔泥彤!
感謝大家能看到完整篇文章欲芹! 在下一篇文章中,我將繼續(xù)分享一個(gè)我封裝的第三方吟吝。這個(gè)第三方里菱父,主要功能都是依賴runtime的。
預(yù)告:下一篇文章將會(huì)在實(shí)戰(zhàn)項(xiàng)目中 運(yùn)用到一下幾個(gè)runtime的方法剑逃,并且會(huì)有詳細(xì)的講解以下方法的作用 歡迎初學(xué)者來留意一下:
class_getInstanceMethod
class_addMethod
method_getImplementation
method_getTypeEncoding
method_exchangeImplementations
objc_setAssociatedObject
objc_getAssociatedObject