Objective-C具有相當多的動態特性,基本的,也是經常被提到和用到的有動態類型(Dynamic typing),動態綁定(Dynamic binding)和動態加載(Dynamic loading)
一、編譯時和運行時
編譯時:即編譯器對語言的編譯階段,編譯時只是對語言進行最基本的檢查和報錯。包括語法分析、詞法分析等等,將程序代碼返程成計算機能識別的語言(例如匯編),編譯通過并不意味著程序就可以成功運行。
運行時:即程序通過編譯這一關后,編譯好的代碼被裝在到內存中這個階段,這個時候會對具體內存進行檢查,而不僅僅對代碼的簡單掃描分析,此時若出錯誤程序會崩潰。
可以說編譯是一個靜態的階段,類型錯誤很明顯可以直接檢查出來,可讀性好,而運行時則是動態的階段,尅是具體與運行環境結合起來。
二、oc語言的動態性
? 含義:oc語言的動態性主要體現在三個方面:動態類型(Dynamic typing)、動態綁定和動態加載。
? 1.動態類型
? 動態類型是指隊形指針類型的動態性,具體是指使用id任意類型將對象的類型確定推遲到運行時,由賦給他的對象類型決定對象指針的類型,另外類型確定推遲到運行時之后,可以通過nsobject的isKindofClass方法動態判斷對象的最后的類型,(動態類型的識別)也就是說id修飾的對象為動態類型的對象,其他在編譯器指明類型的為靜態類型對象,通常如果不需要涉及到多態的話還是要盡量使用靜態類型(原因上面已經說到:錯誤可以在編譯器體檢檢查出來,可讀性好)
示例:
// 編譯的時候人為obj是一個nsstring對象NSString* obj = [[NSData alloc]init];// 編譯通過,運行的時候直接崩潰[obj stringByAppendingString:@"string"];
通過這里就可以知道,將類型的確定延遲到運行時,體現了oc語言的一種動態性:動態類型。
動態類型的識別方法
(1)首先是Class類型
? ? Class class = [NSObject class]; // 通過類名得到對應的Class動態類型
? ? Class class = [obj class];? ? ? ? ?// 通過實例對象得到對應的Class動態類型
? ? if([obj1 class] == [obj2 class])? // 判斷是不是相同類型的實例
(2)Class動態類型和類名字符串的相互轉換
? ? NSClassFromString(@"NSObject");
? ? NSStringFromClass([NSObject class]);
? ? NSStringFromClass([obj class]);
? (3) 判斷對象是否屬于某種動態類型:
? ?- (BOOL)isKindOfClass:class
? ?- (BOOL)? isMemberOfClass:obj?
? (4)判斷類中是否有對應的方法:
? - (BOOL)respondsToSelector:(SEL)selector? // 類中是否有這個類方法
?- (BOOL)instancesResponsdToSelector:(SEL)selector // 判斷對象中是否有這個實例方法
? (5)方法名字符串和SEL類型的轉換
? ? SEL funcID = @select(func);
? ? SEL funcID = NSSelctorFromString(@"func");
? ? NSString* funcName = NSStringFromSelctor(funcID)
2. 動態綁定
動態綁定指的是方法確定的動態性,具體指的是利用OC的消息傳遞機制將要執行的方法的確定推遲到運行時,可以動態添加方法,也就是說,一個OC對象是否調用某個方法不是由編譯器決定的,而是由運行時決定的;另外關于動態綁定的關鍵一點是基于消息傳遞機制的消息轉發機制,主要處理應對一些接受者無法處理的消息,此時有機會將消息轉發給其他接收者處理,具體見下面介紹。
動態綁定是基于動態類型的,在運行時對象的類型確定后,那么對象的屬性和方法也就確定了, 包括類中原來的屬性和方法和運行時動態新加入的屬性和方法,這也就是所謂的動態綁定。動態綁定的核心就是在運行時動態的為類添加屬性和方法,以及方法的最后處理或者轉發,主要用到c語言。#include <objc/runtime.h>
。
消息傳遞機制
在OC中,方法的調用不再理解為對象調用其方法,而是要理解成對象接收消息,消息的發送采用‘動態綁定’機制,具體會調用哪個方法直到運行時才能確定,確定后才會去執行綁定的代碼。方法的調用實際就是告訴對象要干什么,給對象(的指針)傳送一個消息,對象為接收者(receiver),調用的方法及其參數即消息(message),給一個對象傳消息表達為:[receiver message];?接受者的類型可以通過動態類型識別于運行時確定。
在消息傳遞機制中,當開發者編寫[receiver message];語句發送消息后,編譯器都會將其轉換成對應的一條objc_msgSend?C語言消息發送原語,具體格式為:?void objc_msgSend (id self, SEL cmd, ...)
這個原語函數參數可變,第一個參數填入消息的接受者,第二個參數是消息‘選擇子’,后面跟著可選的消息的參數。有了這些參數,objc_msgSend就可以通過接受者的的isa指針,到其類對象中的方法列表中以選擇子的名稱為‘鍵’尋找對應的方法,找到則轉到其實現代碼執行,找不到則繼續根據繼承關系從父類中尋找,如果到了根類還是無法找到對應的方法,說明該接受者對象無法響應該消息,則會觸發‘消息轉發機制’,給開發者最后一次挽救程序崩潰的機會。