OC runtime

1.程序是怎樣運(yùn)行起來的布朦?(以C語言以及VC運(yùn)行環(huán)境為例)
  1. 編輯
  • (把程序代碼輸入煞烫,交給計(jì)算機(jī))。
  1. 編譯(成目標(biāo)程序文件.obj)
  • 編譯就是把高級(jí)語言變成計(jì)算機(jī)可以識(shí)別的2進(jìn)制語言猴鲫,計(jì)算機(jī)只認(rèn)識(shí)1和0对人,編譯程序把人們熟悉的語言換成2進(jìn)制的。
  • 編譯程序把一個(gè)源程序翻譯成目標(biāo)程序的工作過程分為五個(gè)階段:詞法分析拂共;語法分析牺弄;語義檢查和中間代碼生成;代碼優(yōu)化宜狐;目標(biāo)代碼生成势告。主要是進(jìn)行詞法分析和語法分析,又稱為源程序分析抚恒,分析過程中發(fā)現(xiàn)有語法錯(cuò)誤咱台,給出提示信息。
  1. 鏈接(成可執(zhí)行程序文件.exe)俭驮。
  • 鏈接是將編譯產(chǎn)生的.obj文件和系統(tǒng)庫連接裝配成一個(gè)可以執(zhí)行的程序回溺。
  • 為何要將源程序翻譯成可執(zhí)行文件的過程分為編譯和鏈接兩個(gè)獨(dú)立的步驟,不是多此一舉嗎混萝?之所以這樣做遗遵,主要是因?yàn)椋涸谝粋€(gè)較大的復(fù)雜項(xiàng)目中,有很多人共同完成一個(gè)項(xiàng)目(每個(gè)人可能承擔(dān)其中一部分模塊)逸嘀,其中有的模塊可能是用匯編語言寫的车要,有的模塊可能是用VC寫的,有的模塊可能是用VB寫的崭倘,有的模塊可能是購買(不是源程序模塊而是目標(biāo)代碼)或已有的標(biāo)準(zhǔn)庫模塊屯蹦,因此,各類源程序都需要先各自編譯成目標(biāo)程序文件(2進(jìn)行機(jī)器指令代碼)绳姨,再通過鏈接程序?qū)⑦@些目標(biāo)程序文件連接裝配成可執(zhí)行文件登澜。
  1. 運(yùn)行(可執(zhí)行程序文件)。
  • 上述四個(gè)步驟中飘庄,其中第一步的編輯工作是最繁雜而又必須細(xì)致地由人工在計(jì)算機(jī)上來完成脑蠕,其余幾個(gè)步驟則相對(duì)簡(jiǎn)單,基本上由計(jì)算機(jī)來自動(dòng)完成。
2. 動(dòng)態(tài)語言和靜態(tài)語言的在程序不同階段是怎樣處理的谴仙?

編程語言有靜態(tài)和動(dòng)態(tài)之分迂求。

靜態(tài)語言就是,在程序運(yùn)行前決定了所有的類型判斷晃跺,類的所有成員揩局,方法在編譯階段就確定好了內(nèi)存地址,也就意味著所有的類對(duì)象只能訪問屬于自己的成員變量和方法掀虎,否則編譯器直接報(bào)錯(cuò)凌盯。如:java,C++,C

動(dòng)態(tài)語言,類型的判斷烹玉、類的成員變量驰怎、方法的內(nèi)存地址都是在程序的運(yùn)行階段才最終確定,并且還能動(dòng)態(tài)的添加成員變量和方法二打。也就意味著你調(diào)用一個(gè)不存在的方法時(shí)县忌,編譯也能通過,甚至一個(gè)對(duì)象它是什么類型并不是表面我們所看到的那樣,只有運(yùn)行之后才能決定其真正的類型继效。相比于靜態(tài)語言症杏,動(dòng)態(tài)語言具有較高的靈活性和可訂閱性。而OC瑞信,正是一門動(dòng)態(tài)語言鸳慈。

3. runtime
運(yùn)行時(shí):

就是程序在運(yùn)行時(shí)做的一些事。

runtime :

runtime 是OC底層的一套C語言的API喧伞,它是一個(gè)C和匯編寫的動(dòng)態(tài)庫,將OC和C緊密關(guān)聯(lián)绩郎。編譯器最終都會(huì)將OC代碼轉(zhuǎn)化為運(yùn)行時(shí)代碼潘鲫。

runtime這個(gè)系統(tǒng)主要做兩件事 :

1、封裝C語言的結(jié)構(gòu)體和函數(shù)肋杖,讓開發(fā)者在運(yùn)行時(shí)創(chuàng)建溉仑、檢查或者修改類、對(duì)象和方法等等状植。
2浊竟、傳遞消息,找出方法的最終執(zhí)行代碼津畸。

在OC中振定,如果想要某個(gè)對(duì)象傳遞消息,那么就會(huì)使用動(dòng)態(tài)綁定機(jī)制來決定需要調(diào)用的方法肉拓。在底層后频,所有的方法都是普通的C語言函數(shù),然而對(duì)象收到消息之后,究竟該調(diào)用哪個(gè)方法則完全取決于運(yùn)行期決定卑惜,甚至在運(yùn)行時(shí)改變膏执,這些特性使得OC成為一門真正的動(dòng)態(tài)的語言。

OC中的重要工作都由“運(yùn)行期組件”而不是編譯器來完成露久,使用OC面向?qū)ο筇匦运璧娜繑?shù)據(jù)結(jié)構(gòu)及函數(shù)都在運(yùn)行期組件里面更米。例如:運(yùn)行期組件中含有全部的內(nèi)存管理的方法。

在提高性能的方面:只需要更新運(yùn)行期組件毫痕,即可提升應(yīng)用程序的性能征峦。而在那種許多的工作都在編譯期完成的語言,若想要獲得類似的性能提升镇草,則要重新編譯應(yīng)用程序代碼眶痰。

4.要了解運(yùn)行時(shí),我們得先了解OC的消息機(jī)制
4.1 消息發(fā)送(Messaging):是 Runtime 通過 selector(選擇子) 快速查找 IMP 的過程梯啤,有了函數(shù)指針就可以執(zhí)行對(duì)應(yīng)的方法實(shí)現(xiàn)竖伯;

id returnValue = [someObject messageName: parameter];

調(diào)用的runtime函數(shù):
原型:void objc_msgSend(id self, SEL cmd, . . . )
id returnValue = objc_msgSend(someObject,@ selector(messageName:), parameter);

解釋:objc_msgSend函數(shù)會(huì)根據(jù)接受者和選擇子的類型來調(diào)用適當(dāng)?shù)姆椒ā榱私邮胀瓿蛇@個(gè)操作因宇,該方法需要在接收者(someObject)所屬的類中搜尋其“方法列表”七婴,如果能找到就跳轉(zhuǎn)到實(shí)現(xiàn)代碼,若不能察滑,就沿著繼承體系向上查找打厘,找到后在跳轉(zhuǎn),如果最終都找不到贺辰,就執(zhí)行“消息轉(zhuǎn)發(fā)”户盯。

4.2 消息轉(zhuǎn)發(fā)(Message Forwarding):是在查找 IMP 失敗后執(zhí)行一系列轉(zhuǎn)發(fā)流程的慢速通道,如果不作轉(zhuǎn)發(fā)處理饲化,則會(huì)打日志和拋出異常莽鸭。

當(dāng)對(duì)象接受到無法解讀的消息的時(shí)候,就會(huì)啟動(dòng)“消息轉(zhuǎn)發(fā)”機(jī)制吃靠,程序員可以經(jīng)由此過程告訴對(duì)象該如何處理這個(gè)消息硫眨。

消息轉(zhuǎn)發(fā)分為2大階段:

  • 第一階段先征詢接受者,所屬的類巢块,看是否能動(dòng)態(tài)的添加方法礁阁,以處理當(dāng)前這個(gè)“未知的選擇子”,這叫做動(dòng)態(tài)方法解析族奢。
  • 第二階段涉及“完整的消息轉(zhuǎn)發(fā)機(jī)制”姥闭,當(dāng)運(yùn)行期系統(tǒng)已經(jīng)將第一階段執(zhí)行完了,那么系統(tǒng)會(huì)請(qǐng)求接受者以其他的手段來處理與消息相關(guān)的方法調(diào)用越走。1.請(qǐng)接收者看看有沒有備援的接受者可以處理這個(gè)消息泣栈,若有,消息轉(zhuǎn)發(fā)結(jié)束,若還是沒有就啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制南片,運(yùn)行期系統(tǒng)會(huì)把與消息有關(guān)的全部信息封裝到NSInvocation對(duì)象中去掺涛,在給接受者最后一次機(jī)會(huì),令其設(shè)法解決當(dāng)前未處理的這條信息疼进。


    屏幕快照 2017-12-12 15.39.00.png
5.runtime的主要應(yīng)用

(1)替換系統(tǒng)方法

#import "UIImage+ImageLoad.h"
#import <objc/runtime.h>
@implementation UIImage (ImageLoad)

//自定義方法中最后一定要再調(diào)用一下系統(tǒng)的方法薪缆,讓其有加載圖片的功能,但是由于方法交換伞广,系統(tǒng)的方法名已經(jīng)變成了我們自定義的方法名,這就實(shí)現(xiàn)了系統(tǒng)方法的攔截拣帽!
+(UIImage *)xh_imageNamed:(NSString *)name {
    double version = [[UIDevice currentDevice].systemVersion doubleValue];
    if (version >= 7.0) {
        name = [name stringByAppendingString:@"_ios7"];
    }
    return [UIImage xh_imageNamed:name];
    
}


//分類中重寫UIImage的load方法,實(shí)現(xiàn)方法的交換嚼锄,
+(void)load {
    //獲取2個(gè)類的方法
    Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
    Method m2 = class_getClassMethod([UIImage class], @selector(xh_imageNamed:));
    
    //交換
    method_exchangeImplementations(m1, m2);
}

@end

(2)實(shí)現(xiàn)分類關(guān)聯(lián)屬性

#import "UIButton+BtnImageView.h"
#import <objc/runtime.h>

@implementation UIButton (BtnImageView)

-(UIImageView *)btnImageView
{
    // return objc_getAssociatedObject(self, @selector(isClicked));
    return objc_getAssociatedObject(self, &kbtnImageView);
}

//set
static char kbtnImageView;
-(void)setBtnImageView:(UIImageView *)btnImageView
{
    //如果是指針類型
    return objc_setAssociatedObject(self, &kbtnImageView, btnImageView, OBJC_ASSOCIATION_RETAIN);
    
    //1 源對(duì)象self
    //2 關(guān)鍵字 唯一靜態(tài)變量key isClicked
    //3 關(guān)聯(lián)的對(duì)象
    //4 關(guān)鍵策略  OBJC_ASSOCIATION_RETAIN_NONATOMIC
    //objc_setAssociatedObject(self, @selector(isClicked), @(isClicked), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
}
@end

(3)字典轉(zhuǎn)model

(4)歸檔

(5) 萬能控制器跳轉(zhuǎn)

- (void)push:(NSDictionary *)params
{
    // 類名
    NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
    const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
    // 從一個(gè)字串返回一個(gè)類
    Class newClass = objc_getClass(className);
    if (!newClass)
    {
        // 創(chuàng)建一個(gè)類
        Class superClass = [NSObject class];
        newClass = objc_allocateClassPair(superClass, className, 0);
        // 注冊(cè)你創(chuàng)建的這個(gè)類
        objc_registerClassPair(newClass);
    }
    // 創(chuàng)建對(duì)象
    id instance = [[newClass alloc] init];
    // 對(duì)該對(duì)象賦值屬性
    NSDictionary * propertys = params[@"property"];
    [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        // 檢測(cè)這個(gè)對(duì)象是否存在該屬性
        if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
            // 利用kvc賦值
            [instance setValue:obj forKey:key];
        }
    }];
    // 獲取導(dǎo)航控制器
    UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController;
    UINavigationController *pushClassStance = (UINavigationController *)tabVC.viewControllers[tabVC.selectedIndex];
    // 跳轉(zhuǎn)到對(duì)應(yīng)的控制器
    [pushClassStance pushViewController:instance animated:YES];
}

//檢測(cè)是否存在這個(gè)屬性

- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
    unsigned int outCount, i;
    // 獲取對(duì)象里的屬性列表
    objc_property_t * properties = class_copyPropertyList([instance
                                                           class], &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property =properties[i];
        //  屬性名轉(zhuǎn)成字符串
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        // 判斷該屬性是否存在
        if ([propertyName isEqualToString:verifyPropertyName]) {
            free(properties);
            return YES;
        }
    }
    free(properties);
    return NO;
}

(7)插件開發(fā)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末减拭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子区丑,更是在濱河造成了極大的恐慌拧粪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沧侥,死亡現(xiàn)場(chǎng)離奇詭異可霎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宴杀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門癣朗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旺罢,你說我怎么就攤上這事旷余。” “怎么了扁达?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵正卧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我罩驻,道長(zhǎng),這世上最難降的妖魔是什么护赊? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任惠遏,我火速辦了婚禮,結(jié)果婚禮上骏啰,老公的妹妹穿的比我還像新娘节吮。我一直安慰自己,他們只是感情好判耕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布透绩。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帚豪。 梳的紋絲不亂的頭發(fā)上碳竟,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音狸臣,去河邊找鬼莹桅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烛亦,可吹牛的內(nèi)容都是我干的诈泼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼煤禽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铐达!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起檬果,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤瓮孙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后汁汗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷畦,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年知牌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了祈争。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡角寸,死狀恐怖菩混,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扁藕,我是刑警寧澤沮峡,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站亿柑,受9級(jí)特大地震影響邢疙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜望薄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一疟游、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痕支,春花似錦颁虐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽儒陨。三九已至,卻和暖如春笋籽,著一層夾襖步出監(jiān)牢的瞬間蹦漠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工干签, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留津辩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓容劳,卻偏偏與公主長(zhǎng)得像喘沿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子竭贩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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