OC語言的動態(tài)性
OC語言的動態(tài)性主要體現(xiàn)在三個方面:動態(tài)類型(Dynamic typing)、動態(tài)綁定(Dynamic binding)和動態(tài)加載(Dynamic loading)。
動態(tài)類型
??????動態(tài)類型指的是對象指針類型的動態(tài)性,具體是指使用id任意類型將對象的類型確定推遲到運行時,由賦給它的對象類型決定對象指針的類型。另外類型確定推遲到運行時之后,可以通過NSObject的isKindOfClass方法動態(tài)判斷對象最后的類型(動態(tài)類型識別)。也就是說id修飾的對象為動態(tài)類型對象,其他在編譯器指明類型的為靜態(tài)類型對象,通常如果不需要涉及到多態(tài)的話還是要盡量使用靜態(tài)類型(錯誤可以在編譯器提前查出,可讀性好)。
NSString* testObject = [[NSData alloc] init];
??????testObject編譯時指針的類型為NSString,即編譯時會被當成一個NSString實例來處理,編譯器在類型檢查的時候如果發(fā)現(xiàn)類型不匹配則會給出黃色警告,該語句給指針賦值用的是一個NSData對象,則編譯時編譯器則會給出類型不匹配警告。但編譯時如果testObject調(diào)用NSString的方法編譯器會認為是正確的,既不會警告也不會報錯。
??????運行時指針指向的實際是一個NSData對象,因此如果指針調(diào)用了NSString的方法,雖然編譯時通過了,但運行時會崩潰,因為NSData對象沒有該方法;另外,雖然運行時指針實際指向的是NSData,但編譯時編譯器并不知道(編譯器會把指針當成NSString對象處理),因此如果試圖用這個指針調(diào)用NSData的方法會直接編譯不通過,給出紅色報錯,程序也運行不起來。
id testObject = [[NSData alloc] init];
編譯時編譯器把testObject指針當成任意類型,運行時才確定testObject為NSData對象。
動態(tài)綁定
??????動態(tài)綁定指的是方法確定的動態(tài)性,具體指的是利用OC的消息傳遞機制將要執(zhí)行的方法的確定推遲到運行時,可以動態(tài)添加方法。也就是說,一個OC對象是否調(diào)用某個方法不是由編譯器決定的,而是由運行時決定的;另外關于動態(tài)綁定的關鍵一點是基于消息傳遞機制的消息轉(zhuǎn)發(fā)機制,主要處理應對一些接受者無法處理的消息,此時有機會將消息轉(zhuǎn)發(fā)給其他接收者處理,具體見下面介紹。
??????動態(tài)綁定是基于動態(tài)類型的,在運行時對象的類型確定后,那么對象的屬性和方法也就確定了(包括類中原來的屬性和方法以及運行時動態(tài)新加入的屬性和方法),這也就是所謂的動態(tài)綁定了。動態(tài)綁定的核心就該是在運行時動態(tài)的為類添加屬性和方法,以及方法的最后處理或轉(zhuǎn)發(fā),主要用到C語言語法,因為涉及到運行時,因此要引入運行時頭文件:#include <objc/runtime.h>。
消息傳遞機制:
??????在OC中,方法的調(diào)用不再理解為對象調(diào)用其方法,而是要理解成對象接收消息,消息的發(fā)送采用‘動態(tài)綁定’機制,具體會調(diào)用哪個方法直到運行時才能確定,確定后才會去執(zhí)行綁定的代碼。方法的調(diào)用實際就是告訴對象要干什么,給對象(的指針)傳送一個消息,對象為接收者(receiver),調(diào)用的方法及其參數(shù)即消息(message),給一個對象傳消息表達為:[receiver message]; 接受者的類型可以通過動態(tài)類型識別于運行時確定。
??????在消息傳遞機制中,當開發(fā)者編寫[receiver message];語句發(fā)送消息后,編譯器都會將其轉(zhuǎn)換成對應的一條objc_msgSend C語言消息發(fā)送原語,具體格式為:
void objc_msgSend (id self, SEL cmd, ...)
??????這個原語函數(shù)參數(shù)可變,第一個參數(shù)填入消息的接受者,第二個參數(shù)是消息‘選擇子’,后面跟著可選的消息的參數(shù)。有了這些參數(shù),objc_msgSend就可以通過接受者的的isa指針,到其類對象中的方法列表中以選擇子的名稱為‘鍵’尋找對應的方法,找到則轉(zhuǎn)到其實現(xiàn)代碼執(zhí)行,找不到則繼續(xù)根據(jù)繼承關系從父類中尋找,如果到了根類還是無法找到對應的方法,說明該接受者對象無法響應該消息,則會觸發(fā)‘消息轉(zhuǎn)發(fā)機制’,給開發(fā)者最后一次挽救程序崩潰的機會。
動態(tài)加載
??????動態(tài)加載主要包括兩個方面,一個是動態(tài)資源加載,一個是一些可執(zhí)行代碼模塊的加載,這些資源在運行時根據(jù)需要動態(tài)的選擇性的加入到程序中,是一種代碼和資源的‘懶加載’模式,可以降低內(nèi)存需求,提高整個程序的性能,另外也大大提高了可擴展性。
??????例如:資源動態(tài)加載中的圖片資源的屏幕適配,同一個圖片對象可能需要準備幾種不同分辨率的圖片資源,程序會根據(jù)當前的機型動態(tài)選擇加載對應分辨率的圖片,像iphone4之前老機型使用的是@1x的原始圖片,而retina顯示屏出現(xiàn)之后每個像素點被分成了四個像素,因此同樣尺寸的屏幕需要4倍分辨率(寬高各兩倍)的@2x圖片,最新的針對iphone6/6+以上的機型則需要@3x分辨率的圖片。
參考文章