OC執行時訊息

2021-07-24 00:17:06 字數 1721 閱讀 6494

訊息傳送

本章描述內容:訊息表示式是如何轉化成objc_msgsend函式呼叫,和 如何通過明知呼叫方法。然後說明如何利用objc_msgsend函式,並且,有必要時,如何繞開動態繫結。

objc_msgsend函式

在oc中,程式執行之前,訊息是不會繫結到方法實現的。編譯器會將乙個訊息表示式轉化

[receiver message]

;

為對函式objc_msgsend的呼叫。這個函式攜帶訊息——也就是說,selector方法——中提到的接收者和方法名字,作為它兩個主要的引數:

objc_msgsend(receiver, selector);
訊息中所有的引數也提交給objc_msgsend函式:

objc_msgsend(receiver, selector, arg1, arg2, ...);
使用隱含引數

當objc_msgsend找到方法實現的程式時,它呼叫該程式並將所有引數傳遞給訊息。它也傳遞給程式兩個隱含的引數:

1. 接收物件

2. 方法的選擇器

這兩個引數為每個方法的實現提供了關於它呼叫的方法表示式的詳細資訊。它們之所以被稱為「隱含的」,是因為它們並沒有在方法定義的原始碼中宣告。它們在**被編譯時才插入到方法實現中的。

儘管這些引數沒有明確的宣告,原始碼仍然能夠追尋到它們(正如它能追尋到接收物件的例項變數)。乙個方法提及到接收物件如self,涉及自己的選擇器如_cmd。在下面的例子中,_cmd查閱陌生方法中的選擇器,self查閱接收乙個陌生訊息的物件。

- strange

return [target performselector:method];

}

self在兩個引數中更有用。實際上,它是使接收物件的例項變數在方法定義中可用的方式。

獲取方法位址

繞過動態繫結的唯一方法是,獲取方法的位址並直接呼叫它假定它是乙個函式。這可能適用於少部分情況下,當乙個特定的方法將被一連串運作多次並且你想避免方法每次運作訊息傳遞的開銷。

通過nsobject類中定義的乙個方法:methodforselector,你能申請乙個用來實現方法的程式指標,然後用這個指標去呼叫該程式。methodforselector返回的指標必須小心的丟擲合適的函式型別。返回型別和引數型別都應該包含在丟擲中。下面的例子展示了setfailed:方法的實現程式是如何被呼叫的。

void (*setter)(id, sel, bool);

int i;

setter = (void (*)(id, sel, bool))[target

methodforselector:@selector(setfilled:)];

for ( i = 0 ; i < 1000 ; i++ )

setter(targetlist[i], @selector(setfilled:), yes);

頭兩個傳遞給程式的引數是接收物件(self)和方法選擇器(_cmd),這兩個引數在方法語句中是隱藏的,但是當方法被作為函式呼叫時必須明確說明。

使用methodforselector避免動態繫結節約了大部分訊息傳遞需要的時間。然而,節省只有在乙個特定的訊息多次迴圈是才有意義,正如上面for迴圈展示的那樣。

OC執行時動態建立類

it168技術 在前文 深入淺出cocoa之類與物件 一文中,我已經詳細介紹了objc中的 class 與 object 的概念,今天我們來如何在執行時動態建立類。下面這個函式就是應用前面講到的class,metaclass的概念,在執行時動態建立乙個類。這個函式來自 inside mac os x...

執行時異常訊息封裝類

public class serviceruntimeexception extends runtimeexception 使用自定義錯誤訊息 不推薦 param resultcode 錯誤 param message 錯誤訊息 public serviceruntimeexception resu...

OC 執行時語言踩過的坑

最近 遇到了兩次oc 執行時語言的坑,這讓我對此感到深深的敬畏,貼此 警示後人 碰到最多的是,可變陣列nsmutablearray的排序,從伺服器拿下來的array的陣列,進行直接賦值,不幸將nsmutablearray的型別由 nsmutablearray變成了nsarray,在進行接下來的排序時...