初步學習objective c的Runtime機制

2021-09-11 14:03:54 字數 3370 閱讀 1615

objective-c 擴充套件了 c 語言,並加入了物件導向特性和 smalltalk 式的訊息傳遞機制。而這個擴充套件的核心是乙個用 c 和 編譯語言 寫的 runtime 庫。它是 objective-c 物件導向和動態機制的基石。 objective-c 是乙個動態語言,這意味著它不僅需要乙個編譯器,也需要乙個執行時系統來動態得建立類和物件、進行訊息傳遞和**。理解 objective-c 的 runtime 機制可以幫我們更好的了解這個語言,適當的時候還能對語言進行擴充套件,從系統層面解決專案中的一些設計或技術問題。了解 runtime ,要先了解它的核心 - 訊息傳遞 (messaging)。

就像是引言中提到的,了解runtime機制,首先要先了解什麼才是訊息傳遞。 學習過c語言的都能夠理解,c語言的函式呼叫是將程式跳轉到記憶體中的某個位置開始並開始執行對應的**行。而oc中,[object xx(方法名)]並不會直接呼叫對應的**,而是在執行時給object物件傳送了一條訊息,訊息名為xx,這個訊息有可能直接由object處理,也可能被**給另乙個object,還有可能不被任何物件處理,多條不同的訊息可以被同乙個方法實現,以上這些都是在執行時決定的。 通常來說,編譯的時候,方法呼叫的**會被翻譯成c的函式呼叫語句,如下面的兩句是等價的

[array insertobject:obj atindex:2];

objc_msgsend(array, @selector(insertobject:atindex:), obj, 2);

複製**

在oc中,類、物件和方法都是乙個c的結構體,從objc/objc.h標頭檔案中,我們能看到以下定義:

struct objc_object ;

struct objc_class ;

struct objc_method_list ;

struct objc_method ;

複製**

首先,通過obj的isa指標找到它的class;

在class的method list找xx;

如果class中沒有找到xx,繼續往他的superclass中找xx;

一旦找到xx這個函式,就去執行他的實現imp。 如果每次都是走這些流程,那麼這勢必是一種比較低效率的方法,因為乙個class中,只有20%的函式會被經常呼叫,而呼叫率達到80%,因此每當接收到乙個訊息就去遍歷一次objc_method_list是不合理的。所以oc中還是用了另乙個成員:objc_cache。當第一次找到xx之後,就把xx的method_name作為key,把xx的method_imp作為value儲存起來,當再次呼叫xx的時候就直接在cache中找就可以了,減少了對objc_method_list的呼叫次數。

到了這裡,你可能會有疑問,如果在objc_method_list中沒有找到會發生什麼呢?請看下面的內容:

如果沒有在objc_method_list中找到對應的方法,那麼通常情況下,程式會在執行時掛掉並丟擲unrecognized selector sent to … 的異常,但是在異常丟擲之前,oc的執行時會給三次拯救的機會:

method resolution

fast forwarding

normal forwarding

首先,oc執行時會呼叫+resolveinstancemethod:或者+resolveclassmethod:,可以在出現找不到方法的情況的時候提供乙個函式實現。如果在這兩個方法中新增了函式並返回yes,那麼執行時系統將就會重新啟動一次訊息傳送的過程。實現方式如下:

+ (bool)resolveinstancemethod:(sel)asel

return [super resolveinstancemethod];

}void xxmethod(id obj, sel _cmd)

複製**

core data 有用到這個方法。nsmanagedobjects 中 properties 的 getter 和 setter 就是在執行時動態新增的。而如果resolve方法返回no,執行時就會進行下一步:訊息**(message forwarding)。 ps:ios 4.3 加入很多新的 runtime 方法,主要都是以 imp 為字首的方法,比如 imp_implementationwithblock() 用 block 快速建立乙個 imp 。 上面的例子可以重寫成:

imp fooimp = imp_implementationwithblock(^(id _self) );

class_addmethod([self class], asel, fooimp, "v@:");

複製**

如果目標物件實現了-forwardingtargetforselector:,runtime就會在resolve方法返回no時呼叫這個方法,以此來實現訊息的**。實現如下:

- (id)forwardingtargetforselector:(sel)aselector

return [super forwardingtargetforselector:aselector];

}複製**

這個方法中,返回值只要不是nil或者self,就會使訊息傳送的過程被重啟,不過物件會被換成返回的那個物件,否則就會繼續進入下一步:normal forwarding。 fast和normal的區別在於,fast不會建立新的物件,而normal會建立乙個nsinvocation物件,所以fast相對會更快一些。

到這裡,首先runtime會傳送-methodsignatureforselector:訊息獲得函式的引數和返回值型別: · 如果-methodsignatureforselector:返回nil,那麼runtime就會發出-doesnotrecognizeselector:的訊息,程式在這個時候就已經掛掉了; · 如果返回了乙個函式簽名,runtime就會建立乙個nsinvocation物件並傳送-forwardinvocation:訊息給目標物件。 nsinvocation實際是對訊息的描述,包括selector以及引數等資訊,所以可以在-forwardinvocation:裡修改傳進來的nsinvocation物件,然後傳送-invokewithtarget:訊息給他,傳進去乙個新的目標。例項**如下:

- (void)forwardinvocation:(nsinvocation *)invocation

else

}複製**

cocoa 裡很多地方都利用到了訊息傳遞機制來對語言進行擴充套件,如 proxies、nsundomanager 跟 responder chain。nsproxy 就是專門用來作為****訊息的;nsundomanager 擷取乙個訊息之後再傳送;而 responder chain 保證乙個訊息**給合適的響應者。 再次感謝顧鵬的私人部落格,正是參閱了他的文章才進行了這樣的總結,十分感謝。

Objective C檔案操作初步理解

from nsdata 自定義檔案格式,可以處理各種型別的資料 nsdictionary 鍵 值對,處理plist檔案,xml格式,為了保密,也可以存入經過nsdata處理過的資料 nsdata用法 1.寫入檔案 檔案路徑 根目錄 iphonefile資料夾 nsstring path iphone...

Objective C 學習筆記

1 is a 是乙個 繼承,提高執行效率,減少重複 2 has a 有乙個 復合,物件引用其它物件時,利用其它物件特性。3 返回屬性值的訪問方法,名稱中不能使用get這個詞 4 類名首字母大寫,變數首字母小寫。5 在objective c中所有物件間互動都是通過指標實現的。6 指標值被賦值,只有乙個...

Objective c學習筆記

property是object c的乙個特性,可以讓我們輕鬆實現成員變了的setting和getting方法。具體的語法如下 以成員變數nsstring m name為例 標頭檔案中宣告如下 property nsstring m name m檔案實現 synthesize m name 這樣我們便...