1. 程式人生 > >Objective-C是動態語言嗎?為什麼?

Objective-C是動態語言嗎?為什麼?

Objective-C具有相當多的動態特性,基本的,也是經常被提到和用到的有動態型別(Dynamic typing),動態繫結(Dynamic binding)和動態載入(Dynamic loading)。

這些動態特性都是在Cocoa程式開發時非常常用的語言特性,而在這之後,OC在底層也提供了相當豐富的執行時的特性,比如列舉類屬性方法、獲取方法實現等等。雖然在平常的Cocoa開發中這些較底層的執行特性基本用不著,但是在某些情況下如果你知道這些特性併合理加以運用的話,往往能事半功倍~

動態特性基礎

1、動態型別

即執行時再決定物件的型別。這類動態特性在日常應用中非常常見,簡單說就是id型別。id型別即通用的物件類,任何物件都可以被id指標所指,而在實際使用中,往往使用introspection來確定該物件的實際所屬類:

id obj = someInstance;
if ([obj isKindOfClass:someClass])
{
    someClass *classSpecifiedInstance = (someClass *)obj;
    // Do Something to classSpecifiedInstance which now is an instance of someClass
    //...
}

-isMemberOfClass: 是 NSObject 的方法,用以確定某個 NSObject 物件是否是某個類的成員。與之相似的為-isKindOfClass:,可以用以確定某個物件是否是某個類或其子類的成員。這兩個方法為典型的introspection方法。在確定物件為某類成員後,可以安全地進行強制轉換,繼續之後的工作。

2、動態繫結

基於動態型別,在某個例項物件被確定後,其型別便被確定了。該物件對應的屬性和響應的訊息也被完全確定,這就是動態繫結。在繼續之前,需要明確Objective-C中訊息的概念。由於OC的動態特性,在OC中其實很少提及“函式”的概念,傳統的函式一般在編譯時就已經把引數資訊和函式實現打包到編譯後的原始碼中了,而在OC中最常使用的是訊息機制。呼叫一個例項的方法,所做的是向該例項的指標傳送訊息,例項在收到訊息後,從自身的實現中尋找響應這條訊息的方法。

動態繫結所做的,即是在例項所屬類確定後,將某些屬性和相應的方法繫結到例項上。這裡所指的屬性和方法當然包括了原來沒有在類中實現的,而是在執行時才需要的新加入的實現。在Cocoa層,我們一般向一個NSObject物件傳送-respondsToSelector:或者-instancesRespondToSelector:等來確定物件是否可以對某個SEL做出響應,而在OC訊息轉發機制被觸發之前,對應的類的+resolveClassMethod:和+resolveInstanceMethod:將會被呼叫,在此時有機會動態地向類或者例項新增新的方法,也即類的實現是可以動態繫結的。一個例子:

void dynamicMethodIMP(id self, SEL _cmd)
{
    // implementation ....
}



//該方法在OC訊息轉發生效前被呼叫
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{ 
    if (aSEL == @selector(resolveThisMethodDynamically)) {
        //向[self class]中新加入返回為void的實現,SEL名字為aSEL,實現的具體內容為dynamicMethodIMP class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, “[email protected]:”);
        return YES;
    }
    return [super resolveInstanceMethod:aSel];
}  

當然也可以在任意需要的地方呼叫class_addMethod或者method_setImplementation(前者新增實現,後者替換實現),來完成動態繫結的需求。

3、動態載入

根據需求載入所需要的資源,這點很容易理解,對於iOS開發來說,基本就是根據不同的機型做適配。最經典的例子就是在Retina裝置上載入@2x的圖片,而在老一些的普通屏裝置上載入原圖。隨著Retina iPad的推出,和之後可能的Retina Mac的出現,這個特性相信會被越來越多地使用。

深入執行時特性

基本的動態特性在常規的Cocoa開發中非常常用,特別是動態型別和動態繫結。由於Cocoa程式大量地使用Protocol-Delegate的設計模式,因此絕大部分的delegate指標型別必須是id,以滿足執行時delegate的動態替換(在Java裡這個設計模式被叫做Strategy?不是很懂Java,求糾正)。而Objective-C還有一些高階或者說更底層的執行時特性,在一般的Cocoa開發中較為少見,基本被運用與編寫OC和其他語言的介面上。但是如果有所瞭解並使用得當的話,在Cocoa開發中往往可以輕易解決一些棘手問題。

這類執行時特性大多由/usr/lib/libobjc.A.dylib這個動態庫提供,裡面包括了對於類、例項成員、成員方法和訊息傳送的很多API,包括獲取類例項變數列表,替換類中的方法,為類成員新增變數,動態改變方法實現等,十分強大。完整的API列表和手冊可以在這裡找到。雖然文件開頭表明是對於Mac OS X Objective-C 2.0適用,但是由於這些是OC的底層方法,因此對於iOS開發來說也是完全相同的。

一個簡單的例子,比如在開發Universal應用或者遊戲時,如果使用IB構建了大量的自定義的UI,那麼在由iPhone版轉向iPad版的過程中所面臨的一個重要問題就是如何從不同的nib中載入介面。在iOS5之前,所有的UIViewController在使用預設的介面載入時(init或者initWithNibName:bundle:),都會走-loadNibNamed:owner:options:。而因為我們無法拿到-loadNibNamed:owner:options的實現,因此對其過載是比較困難而且存在風險的。因此在做iPad版本的nib時,一個簡單的辦法是將所有的nib的命名方式統一,然後使用自己實現的新的類似-loadNibNamed:owner:options的方法將原方法替換掉,同時保證非iPad的裝置還走原來的loadNibNamed:owner:options方法。使用OC執行時特性可以較簡單地完成這一任務。

程式碼如下,在程式執行時呼叫+swizze,交換自己實現的loadPadNibNamed:owner:options和系統的loadNibNamed:owner:options,之後所有的loadNibNamed:owner:options訊息都將會發為loadPadNibNamed:owner:options,由自己的程式碼進行處理。

+(BOOL)swizze {
    Method oldMethod = class_getInstanceMethod(self, @selector(loadNibNamed:owner:options:));
    if (!oldMethod) {
        return NO;
    }
    Method newMethod = class_getInstanceMethod(self, @selector(loadPadNibNamed:owner:options:));
    if (!newMethod) {
        return NO;
    }
    method_exchangeImplementations(oldMethod, newMethod);
    return YES;
}  

loadPadNibNamed:owner:options的實現如下,注意在其中的loadPadNibNamed:owner:options由於之前已經進行了交換,因此實際會發送為系統的loadNibNamed:owner:options。以此完成了對不同資源的載入。

-(NSArray *)loadPadNibNamed:(NSString *)name owner:(id)owner options:(NSDictionary *)options {
    NSString *newName = [name stringByReplacingOccurrencesOfString:@"@pad" withString:@""];
    newName = [newName stringByAppendingFormat:@"@pad"];
    //判斷是否存在
    NSFileManager *fm = [NSFileManager defaultManager];
    NSString* filepath = [[NSBundle mainBundle] pathForResource:newName ofType:@”nib”];
    //這裡呼叫的loadPadNibNamed:owner:options:實際為為交換後的方法,即loadNibNamed:owner:options:
    if ([fm fileExistsAtPath:filepath]) {
        return [self loadPadNibNamed:newName owner:owner options:options];
    } else {
        return [self loadPadNibNamed:name owner:owner options:options]; 
    }
}  

當然這只是一個簡單的例子,而且這個功能也可以通過別的方法來實現。比如新增UIViewController的類別來過載init,但是這樣的過載會比較危險,因為你UIViewController的實現你無法完全知道,因此可能會由於過載導致某些本來應有的init程式碼沒有覆蓋,從而出現不可預測的錯誤。當然在上面這個例子中過載VC的init的話沒有什麼問題(因為對於VC,init的方法會被自動轉發為loadNibNamed:owner:options,因此init方法並沒有做其他更復雜的事情,因此只要初始化VC時使用的都是init的話就沒有問題)。但是並不能保證這樣的過載對於其他類也是可行的。因此對於實現未知的系統方法,使用上面的執行時交換方法會是一個不錯的選擇~


相關推薦

Objective-C動態語言?為什麼?

Objective-C具有相當多的動態特性,基本的,也是經常被提到和用到的有動態型別(Dynamic typing),動態繫結(Dynamic binding)和動態載入(Dynamic loading)。 這些動態特性都是在Cocoa程式開發時非常常用的語言特性,而在這之後,OC在底層也提供了相當豐富

Objective-C 程式語言(13)遠端訊息---分散式物件

遠端訊息 和其他語言一樣,Objective-C語言最初設的設計也是針對在同一地址空間中執行的單一程序而設計的。 然而,在面向物件的模型中,通訊是執行時在相對自我包含的單元之間通過訊息的方式來進行的。這種方式看起來很適合程序間的通訊。因此,不同地址空間中的物件互發訊息或

Objective-C 程式語言官網文件(五)-屬性的宣告

Declared Properties The Objective-C declared properties feature provides a simple way to declare and implement an object’s accessor methods. Ov

Objective-C 程式語言官網文件(十三 終結篇)-詞彙表

Glossary abstract class   A class that’s defined solely so that other classes can inherit from it. Programs don’t use instances of an abstract class; the

Objective-C動態執行時語言的個人理解

      以前開發時沒有特別注意這些細節問題,今天突然被問到,一下子懵圈了,經過一番查詢和比較,再加上小編的理解終於是瞭解的差不多了,現在分享給大家! 1、什麼是動態語言? 動態語言,是指程式在執行

第 1 條:了解 Objective-C 語言的起源

還在 特性 只知道 程序 開發 不能 核心 nbsp 原因   馬上就要發布 Swift 4 了,自己也在學習 Swift,後面 iOS 編程估計也快是 Swift 的天下了,我卻還在這抱著一本講 OC 的書在啃,怪只能怪自己之前太懶了,按定價好幾十塊錢買的書不讀完,簡直對

iOS開發核心語言Objective C —— 面向對象思維、setter和getter方法及點語法

才幹 各路 alt .net 行為 變量的作用域 fadein 格式 讀取 本分享是面向有意向從事iOS開發的夥伴們。或者已經從事了iOS的開發人員。假設您對iOS開發有極高的興趣,能夠與我一起探討iOS開發。一起學習,共同進步。假設您是零基礎,建議您先

Objective-C多態:動態類型識別+動態綁定+動態加載

出錯 靜態類 檢查 而不是 memberof ati 運行 strong 函數指針 http://blog.csdn.net/tskyfree/article/details/7984887 一、Objective-C多態 1.概念:相同接口,不同的實現 來自不同類可以定義

Objective-C中,類方法的getter和setter可以用點運算符

clang col 靜態變量 變量 uri family lan getc sta Objective-C中,對象實例property的getter和setter可以使用點運算符來操作,那麽類方法的getter和setter可以使用點運算嗎? 答案是肯定的。 看如下代碼

Objective-C語言基礎與總結

什麼是Objective-C Objective-C是C語言的一個超集,具有面向物件的特性,並具備了強大的執行時動態語言特性。 Objective-C的優缺點 優點: 作為C語言的超級,在C語言的基礎上衍生了很多新的語言特徵,封裝的很完善且使用方便,大大降低了程式設

你在學習C語言?這些C語言專業書籍,你讀過幾本?

C語言誕生背景 1964 年,貝爾實驗室加入了通用電氣和麻省理工學院發起的計劃 MULTICS(一套安裝在大型主機上的分時多工作業系統)。由於專案進展緩慢,1969 年,貝爾實驗室宣佈退出。做 MULTICS 專案的時候,貝爾實驗室的工程師 Ken Thompson 寫了個遊戲 Space Tr

GO語言生成C動態庫,再被連結成新動態

目錄 目標 測試程式碼 編譯步驟 GO ----> 動態庫 再封裝成新動態庫 編譯生成可執行檔案 嘗試GO---->C靜態庫---->C動態庫。 目標 如果想把GO語言實現的功能整合到C固定介面上,中間需要多加一次封裝。 因為很難用GO直

objective-c語言學習筆記

1、c語言風格函式申明 int add(int a, int b);     oc語言為 (int)add:(int)a par2:(int) b; 函式名add也是第一個引數名稱,第二個引數名稱是par2,這樣處理是為了實現函式的多型性。  

深入Objective-C動態特性

目錄(?)[-] 動態語言基礎 深入執行時  Objective-C有相當多的動態特性,基本上也是最常用的有動態型別(Dynamic typing)、動態繫結(Dynamic binding)和動態載入(Dynamic loading),這些都是在

c++之前需要先學c語言

相信很多想學或學過C語言或C++的朋友們都有這樣一個困惑:C和C++到底有什麼區別?學C++之前需要學C語言嗎?那麼今天小編就來為大家解答這個疑惑! 一、C和C++的區別: C語言是面向過程的,而C++是面向物件的 C是一個結構化語言,它的重點在於演算法和資料結構。C程式的設計首要考

嵌入式知識分享:嵌入式學習需要精通C++語言

嵌入式學習需要精通C++嗎? 假設把對C/C++的瞭解程度分為入門,熟悉,精通。「精通」之後再也沒有更高階的形容詞描述了,那麼其實題主只要達到熟悉C/C++就足夠了。 嗯?我並不是指熟悉C/C++的語法。還有,問這個問題的小夥伴說的嵌入式開發是指微控制器裸機開

Objective-CC語言使用初步學習

最近在進行iOS的深入學習,看過一些部落格後意識到自己的程式碼寫的過於臃腫。我從開始學習到現在的業務熟練都是使用的最基本的MVC模式,於是MVC中的C--controller程式碼十分臃腫,讓接手程式碼的人無從下手。在網上查閱多篇部落格後,才瞭解到有多種設計模式,雖然各有缺點,但是能讓我借鑑到許多方

從零開始學習swift語言(Objective-C轉學swift)-( 一 )簡介學習背景及開發工具

簡介學習背景 本人之前使用Objective-C做了三年左右的iOS開發,之前一直想學習swift語言可惜公司專案比較緊一直沒有時間.現在每天倒是可以抽時間來學習swift,之後我會在這裡記錄下來我的學習歷程,並且會列舉出swift語言和Objectiv

大學生學程式設計(七):學習C++必須先學C語言

很多初學程式設計的人都比較困惑和迷茫,C語言和C++到底有什麼區別和聯絡?學習C++是不是可以直接跳過C語言? 其實這個問題不難,就是直接瞭解兩者的聯絡和區別就可以給出答案。 歡迎加入學習群【892643663】,獲取全套免費C/C++企業實戰級課程資源(素材+原始碼+視訊)和編譯大

第21屆IOCCC大賽獲獎作品,看得懂這些C語言

大家可能一直覺得程式碼簡潔易懂才是我們所膜拜的,但恰恰有個組織卻在比賽誰的程式碼可讀性更差……它就是IOCCC…… 首先科普下IOCCC,其英文全稱是“The International Obfuscated C Code Contest”,中文名為“國際C語言混亂程式碼大賽”。IOCCC是一項國際