|
Objective-C具有相當(dāng)多的動(dòng)態(tài)特性,基本的,也是經(jīng)常被提到和用到的有動(dòng)態(tài)類型(Dynamic typing),動(dòng)態(tài)綁定(Dynamic binding)和動(dòng)態(tài)加載(Dynamic loading)。 這些動(dòng)態(tài)特性都是在Cocoa程序開(kāi)發(fā)時(shí)非常常用的語(yǔ)言特性,而在這之后,OC在底層也提供了相當(dāng)豐富的運(yùn)行時(shí)的特性,比如枚舉類屬性方法、獲取方法實(shí)現(xiàn)等等。雖然在平常的Cocoa開(kāi)發(fā)中這些較底層的運(yùn)行特性基本用不著,但是在某些情況下如果你知道這些特性并合理加以運(yùn)用的話,往往能事半功倍~ 動(dòng)態(tài)特性基礎(chǔ)1、動(dòng)態(tài)類型 即運(yùn)行時(shí)再?zèng)Q定對(duì)象的類型。這類動(dòng)態(tài)特性在日常應(yīng)用中非常常見(jiàn),簡(jiǎn)單說(shuō)就是id類型。id類型即通用的對(duì)象類,任何對(duì)象都可以被id指針?biāo)福趯?shí)際使用中,往往使用introspection來(lái)確定該對(duì)象的實(shí)際所屬類:
2、動(dòng)態(tài)綁定 基于動(dòng)態(tài)類型,在某個(gè)實(shí)例對(duì)象被確定后,其類型便被確定了。該對(duì)象對(duì)應(yīng)的屬性和響應(yīng)的消息也被完全確定,這就是動(dòng)態(tài)綁定。在繼續(xù)之前,需要明確Objective-C中消息的概念。由于OC的動(dòng)態(tài)特性,在OC中其實(shí)很少提及“函數(shù)”的概念,傳統(tǒng)的函數(shù)一般在編譯時(shí)就已經(jīng)把參數(shù)信息和函數(shù)實(shí)現(xiàn)打包到編譯后的源碼中了,而在OC中最常使用的是消息機(jī)制。調(diào)用一個(gè)實(shí)例的方法,所做的是向該實(shí)例的指針發(fā)送消息,實(shí)例在收到消息后,從自身的實(shí)現(xiàn)中尋找響應(yīng)這條消息的方法。 動(dòng)態(tài)綁定所做的,即是在實(shí)例所屬類確定后,將某些屬性和相應(yīng)的方法綁定到實(shí)例上。這里所指的屬性和方法當(dāng)然包括了原來(lái)沒(méi)有在類中實(shí)現(xiàn)的,而是在運(yùn)行時(shí)才需要的新加入的實(shí)現(xiàn)。在Cocoa層,我們一般向一個(gè)NSObject對(duì)象發(fā)送-respondsToSelector:或者-instancesRespondToSelector:等來(lái)確定對(duì)象是否可以對(duì)某個(gè)SEL做出響應(yīng),而在OC消息轉(zhuǎn)發(fā)機(jī)制被觸發(fā)之前,對(duì)應(yīng)的類的+resolveClassMethod:和+resolveInstanceMethod:將會(huì)被調(diào)用,在此時(shí)有機(jī)會(huì)動(dòng)態(tài)地向類或者實(shí)例添加新的方法,也即類的實(shí)現(xiàn)是可以動(dòng)態(tài)綁定的。一個(gè)例子:
當(dāng)然也可以在任意需要的地方調(diào)用 3、動(dòng)態(tài)加載 根據(jù)需求加載所需要的資源,這點(diǎn)很容易理解,對(duì)于iOS開(kāi)發(fā)來(lái)說(shuō),基本就是根據(jù)不同的機(jī)型做適配。最經(jīng)典的例子就是在Retina設(shè)備上加載@2x的圖片,而在老一些的普通屏設(shè)備上加載原圖。隨著Retina iPad的推出,和之后可能的Retina Mac的出現(xiàn),這個(gè)特性相信會(huì)被越來(lái)越多地使用。 深入運(yùn)行時(shí)特性基本的動(dòng)態(tài)特性在常規(guī)的Cocoa開(kāi)發(fā)中非常常用,特別是動(dòng)態(tài)類型和動(dòng)態(tài)綁定。由于Cocoa程序大量地使用Protocol-Delegate的設(shè)計(jì)模式,因此絕大部分的delegate指針類型必須是id,以滿足運(yùn)行時(shí)delegate的動(dòng)態(tài)替換(在Java里這個(gè)設(shè)計(jì)模式被叫做Strategy?不是很懂Java,求糾正)。而Objective-C還有一些高級(jí)或者說(shuō)更底層的運(yùn)行時(shí)特性,在一般的Cocoa開(kāi)發(fā)中較為少見(jiàn),基本被運(yùn)用與編寫(xiě)OC和其他語(yǔ)言的接口上。但是如果有所了解并使用得當(dāng)?shù)脑?,在Cocoa開(kāi)發(fā)中往往可以輕易解決一些棘手問(wèn)題。 這類運(yùn)行時(shí)特性大多由 一個(gè)簡(jiǎn)單的例子,比如在開(kāi)發(fā)Universal應(yīng)用或者游戲時(shí),如果使用IB構(gòu)建了大量的自定義的UI,那么在由iPhone版轉(zhuǎn)向iPad版的過(guò)程中所面臨的一個(gè)重要問(wèn)題就是如何從不同的nib中加載界面。在iOS5之前,所有的 代碼如下,在程序運(yùn)行時(shí)調(diào)用
當(dāng)然這只是一個(gè)簡(jiǎn)單的例子,而且這個(gè)功能也可以通過(guò)別的方法來(lái)實(shí)現(xiàn)。比如添加UIViewController的類別來(lái)重載init,但是這樣的重載會(huì)比較危險(xiǎn),因?yàn)槟鉛IViewController的實(shí)現(xiàn)你無(wú)法完全知道,因此可能會(huì)由于重載導(dǎo)致某些本來(lái)應(yīng)有的init代碼沒(méi)有覆蓋,從而出現(xiàn)不可預(yù)測(cè)的錯(cuò)誤。當(dāng)然在上面這個(gè)例子中重載VC的init的話沒(méi)有什么問(wèn)題(因?yàn)閷?duì)于VC,init的方法會(huì)被自動(dòng)轉(zhuǎn)發(fā)為loadNibNamed:owner:options,因此init方法并沒(méi)有做其他更復(fù)雜的事情,因此只要初始化VC時(shí)使用的都是init的話就沒(méi)有問(wèn)題)。但是并不能保證這樣的重載對(duì)于其他類也是可行的。因此對(duì)于實(shí)現(xiàn)未知的系統(tǒng)方法,使用上面的運(yùn)行時(shí)交換方法會(huì)是一個(gè)不錯(cuò)的選擇~ |
|
|