oc是一個(gè)全動(dòng)態(tài)語(yǔ)言裆蒸,oc的一切都是基于runtime實(shí)現(xiàn)的熔萧!
從以下三方面來(lái)理解runtime吧!
1. 傳統(tǒng)的面向過(guò)程的語(yǔ)言開(kāi)發(fā)僚祷,例如c語(yǔ)言佛致。實(shí)現(xiàn)c語(yǔ)言編譯器很簡(jiǎn)單,只要按照語(yǔ)法規(guī)則實(shí)現(xiàn)一個(gè)LALR語(yǔ)法分析器就可以了辙谜,編譯器優(yōu)化是非常難的topic俺榆,不在這里討論范圍內(nèi),忽略装哆。 這里我們實(shí)現(xiàn)了編譯器其中最最基礎(chǔ)和原始的目標(biāo)之一就是把一份代碼里的函數(shù)名稱罐脊,轉(zhuǎn)化成一個(gè)相對(duì)內(nèi)存地址定嗓,把調(diào)用這個(gè)函數(shù)的語(yǔ)句轉(zhuǎn)換成一個(gè)jmp跳轉(zhuǎn)指令。在程序開(kāi)始運(yùn)行時(shí)候萍桌,調(diào)用語(yǔ)句可以正確跳轉(zhuǎn)到對(duì)應(yīng)的函數(shù)地址宵溅。 這樣很好,也很直白上炎,但是恃逻。。反症。太死板了辛块。everything is per-determined
2. 我們希望靈活,于是需要開(kāi)發(fā)面向?qū)ο蟮恼Z(yǔ)言铅碍,例如c++润绵。 c++在c的基礎(chǔ)上增加了類(lèi)的部分。但這到底意味著什么呢胞谈?我們?cè)趯?xiě)它的編譯器要如何考慮呢尘盼?其實(shí),就是讓編譯器多繞個(gè)彎烦绳,在嚴(yán)格的c編譯器上增加一層類(lèi)處理的機(jī)制卿捎,把一個(gè)函數(shù)限制在它處在的class環(huán)境里,每次請(qǐng)求一個(gè)函數(shù)調(diào)用径密,先找到它的對(duì)象, 其類(lèi)型,返回值午阵,參數(shù)等等,確定了這些后再jmp跳轉(zhuǎn)到需要的函數(shù)享扔。這樣很多程序增加了靈活性同樣一個(gè)函數(shù)調(diào)用會(huì)根據(jù)請(qǐng)求參數(shù)和類(lèi)的環(huán)境返回完全不同的結(jié)果底桂。增加類(lèi)機(jī)制后,就模擬了現(xiàn)實(shí)世界的抽象模式惧眠,不同的對(duì)象有不同的屬性和方法籽懦。同樣的方法,不同的類(lèi)有不同的行為氛魁! 這里大家就可以看到作為一個(gè)編譯器開(kāi)發(fā)者都做了哪些進(jìn)一步的思考暮顺。但是。秀存。捶码。還是死板, 我們?nèi)匀唤衏++是static language。
3. 希望更加靈活或链! 于是我們完全把上面哪個(gè)類(lèi)的實(shí)現(xiàn)部分抽象出來(lái)宙项,做成一套完整運(yùn)行階段的檢測(cè)環(huán)境。這次再寫(xiě)編譯器甚至保留部分代碼里的sytax名稱株扛,名稱錯(cuò)誤檢測(cè)尤筐,runtime環(huán)境注冊(cè)所有全局的類(lèi),函數(shù)洞就,變量等等信息等等盆繁,我們可以無(wú)限的為這個(gè)層增加必要的功能。調(diào)用函數(shù)時(shí)候旬蟋,會(huì)先從這個(gè)運(yùn)行時(shí)環(huán)境里檢測(cè)所以可能的參數(shù)再做jmp跳轉(zhuǎn)油昂,這就是runtime。編譯器開(kāi)發(fā)起來(lái)比上面更加彎彎繞倾贰。但是這個(gè)層極大增加了程序的靈活性冕碟。? 例如當(dāng)調(diào)用一個(gè)函數(shù)時(shí)候,前2種語(yǔ)言匆浙,很有可能一個(gè)jmp到了一個(gè)非法地址導(dǎo)致程序crash, 但是在這個(gè)層次里面安寺,runtime就過(guò)濾掉了這些可能性。 這就是為什么dynamic langauge更加強(qiáng)壯首尼。 因?yàn)榫幾g器和runtime環(huán)境開(kāi)發(fā)人員已經(jīng)幫你處理了這些問(wèn)題挑庶。
好了上面說(shuō)著這么多,我們?cè)俜祷貋?lái)看objective-c.? 現(xiàn)在你是不是能理解這樣的語(yǔ)句了呢软能?
id obj=self;
if ([obj respondsToSelector:@selector(function1:)) {
}
if ([obj isKindOfClass:[NSArray class]] ) {
}
if ([obj conformsToProtocol:@protocol(myProtocol)]) {
}
if ([[obj class] isSubclassOfClass:[NSArray class]]) {
}
[obj someNonExistFunction];
看似很簡(jiǎn)單的語(yǔ)句迎捺,但是為了讓語(yǔ)言實(shí)現(xiàn)這個(gè)能力,語(yǔ)言開(kāi)發(fā)者要付出很多努力實(shí)現(xiàn)runtime環(huán)境查排。這里運(yùn)行時(shí)環(huán)境處理了弱類(lèi)型凳枝、函數(shù)存在檢查工作。runtime會(huì)檢測(cè)注冊(cè)列表里是否存在對(duì)應(yīng)的函數(shù)跋核,類(lèi)型是否正確岖瑰,最后確定下來(lái)正確的函數(shù)地址,再進(jìn)行保存寄存器狀態(tài)了罪,壓棧锭环,函數(shù)調(diào)用等等實(shí)際的操作。
id knife=[Knife grateKnife];
NSArray *monsterList=[NSArray array];
[monsterList makeObjectsPerformSelector:@selector(killMonster:) withObject:knife];
在c,c++年代去完成這個(gè)功能是非常麻煩的泊藕,但是動(dòng)態(tài)語(yǔ)言卻非常簡(jiǎn)單辅辩。
關(guān)于執(zhí)行效率問(wèn)題。 “靜態(tài)語(yǔ)言執(zhí)行效率要比動(dòng)態(tài)語(yǔ)言高”娃圆,這句沒(méi)錯(cuò)玫锋。因?yàn)橐徊糠謈pu計(jì)算損耗在了runtime過(guò)程中。而靜態(tài)語(yǔ)言生成的機(jī)器指令更簡(jiǎn)潔讼呢。正因?yàn)橹肋@個(gè)原因撩鹿,所以開(kāi)發(fā)語(yǔ)言的人付出很大一部分努力為了保持runtime小巧上。所以objecitve-c是c的超集+一個(gè)小巧的runtime環(huán)境悦屏。但是节沦,換句話說(shuō)键思,從算法角度考慮,這點(diǎn)復(fù)雜度不算差別的甫贯,Big O notation結(jié)果不會(huì)有差別吼鳞。( It's not log(n) vs n^2 )
簡(jiǎn)單理解:“Runtime is everything between your each function call.”
Runtime好比objective-c的靈魂。很多東西都是在這個(gè)基礎(chǔ)上出現(xiàn)的叫搁。所以它是指的你花功夫去理解的赔桌。