1. 程式人生 > >Objc中向一個nil物件傳送訊息會怎樣

Objc中向一個nil物件傳送訊息會怎樣

我們知道在 Objective-C 中給 nil 傳送訊息程式不會崩潰,

Objective-C 是以 C 語言為基礎的,

PC 上,在 C 語言中對空指標進行操作,

程式會由於越界訪問而出現保護錯進而崩潰,

但是 Objective-C 中為什麼不會崩潰呢?

原因需要從原始碼中尋找,

下面是 objc_msgSend 的 arm 版彙編程式碼片段:

在 arm 的函式呼叫過程中,

一般用 r0-r4 傳遞引數,

用 r0 傳遞返回值。

對應 objc_msgSend,第一個引數為 self,返回值也是 self,都放在 r0(a1)中。

 

 

/********************************************************************

 * idobjc_msgSend(idself, SELop, ...)

 * On entry: a1 is the message receiver,

 *                  a2 is the selector

 ********************************************************************/

 

ENTRY objc_msgSend

# check whether receiver is nil

teq     a1, #0

moveq   a2, #0

bxeq    lr

 

teq 指令說明:

TEQ RnOperand2 The TEQ instruction performs a bitwise Exclusive OR operation on the value in Rn and the value of Operand2.

測試 self 是否為空。

moveq 指令說明:

如果self為空,則將 selector 也設定為空。

bx 指令說明:

在 arm 中 bx lr 用來返回到呼叫子程式的地方(即:返回到呼叫者),此處是:如果 self 為空,就返回到呼叫 objc_msgSend 的地方繼續執行。

總之:

如果傳遞給 objc_msgSend 的 self 引數是 nil,該函式不會執行有意義的操作,直接返回。

因為OC的函式都是通過objc_msgSend進行訊息傳送來實現的,相對於C和C++來說,對於空指標的操作會引起crash問題,而objc_msgSend會通過判斷self來決定是否傳送訊息,如果self為nil,那麼selector也會為空,直接返回,不會出現問題。視方法返回值,向nil發訊息可能會返回nil(返回值為物件),0(返回值為一些基礎資料)或 返回值為結構體,傳送給 nil 的訊息將返回0,結構體中各個欄位的值將都是0,等等。但對於[NSNull null]物件傳送訊息時,是會crash的,因為NSNull類只有一個null方法。