[英]NSInvocation needing NSMethodSignature
我一直想知道NSInvocation
是否需要NSMethodSignature
。 假設我們要編寫自己的NSInvocation,我的要求將是這樣的:
SEL
然后,我將從目標和SEL
獲取IMP
,並將argument
作為參數傳遞。
所以,我的問題是,為什么我們需要一個NSMethodSignature
來構造和使用NSInvocation
?
注意:我確實知道,只有一個SEL
和一個目標,我們沒有此方法的參數和返回類型,但是為什么我們要關心args和return的類型呢?
C中的每種類型都有不同的大小。 (即使相同的類型在不同的系統上可能具有不同的大小,但現在我們將忽略它。) int
可以具有32位或64位,具體取決於系統。 double
需要64位。 char
表示8位(但可能會作為常規int
傳遞,具體取決於系統的傳遞約定)。 最后也是最重要的是, struct
類型的大小各不相同,具體取決於其中的元素數量和大小。 沒有任何限制。 因此,無論類型如何,都不可能以相同的方式傳遞參數。 因此,調用函數如何安排參數,以及被調用函數如何解釋其參數,必須取決於函數的簽名。 (不能有類型無關的“參數數組”;數組元素的大小是多少?)編譯正常的函數調用時,編譯器會在編譯時知道簽名,並可以根據調用約定正確地安排簽名。 但是NSInvocation
是用於在運行時管理調用的。 因此,它需要方法簽名的表示才能起作用。
NSInvocation
可以做幾件事。 所有這些都需要了解參數的數量和類型(至少是類型的大小):
NSInvocation
對象並將其傳遞給-forwardInvocation:
NSInvocation
對象包含所有已傳遞參數的副本,因為可以稍后存儲和調用它。 因此,運行時至少需要知道參數總數,以便從寄存器和/或堆棧中復制正確數量的數據(取決於調用約定中參數的排列方式)到NSInvocation
對象。 NSInvocation
對象時,可以使用-getArgument:atIndex:
查詢第i個參數的值。 您還可以使用-setArgument:atIndex:
設置/更改第i個參數的值。 這要求它知道1)第i個參數在其數據緩沖區的何處開始; 這需要知道先前的參數有多大,以及2)第i個參數有多大,以便它可以復制正確數量的數據(如果復制的數據太少,它將具有損壞的值;如果復制的數據也太多)比如說,當您執行getArgument
,它可以覆蓋您提供給它的緩沖區;或者當您執行setArgument
,可以覆蓋其他參數)。 -retainArguments
,這將使其保留對象指針類型的所有參數。 這要求它區分對象指針類型和其他類型,因此類型信息不僅必須包括大小。 NSInvocation
,這將導致它構造並執行對該方法的調用。 這要求它至少知道要從其緩沖區復制到寄存器/堆棧中的數據量,以將所有數據放置在函數期望的位置。 這至少需要知道所有參數的組合大小,並且可能還需要知道單個參數的大小,以便可以正確找出寄存器上的參數和堆棧上的參數之間的鴻溝。 您可以使用-getReturnValue:
獲得調用的返回值-getReturnValue:
這與上面的論證有類似的問題。
struct
類型時,調用約定非常不同-實際上,在所有常規參數之前添加了一個附加(第一個)參數,該參數是指向的指針。結構結果應寫入的空間。 這不是常規的調用約定,在常規的調用約定中,結果在寄存器中返回。 (在PowerPC中,我認為double
返回類型也得到了特殊處理。)因此,知道返回類型本質上是用於構造和調用NSInvocation
。 消息發送和轉發機制必須正常運行才能使用NSMethodSignature進行調用。 NSMethodSignature和NSInvocation是圍繞__builtin_call()
的包裝而構建的,__builtin_call __builtin_call()
既依賴於體系結構,又對給定函數所需的堆棧空間非常保守。 因此,當調用被調用時, __builtin_call()
從方法簽名中獲取所有需要的信息,並且可以通過將調用扔給轉發機制而優雅地失敗,因為它知道它也收到了有關堆棧外觀的正確信息。重新調用。
話雖這么說,但如果沒有方法簽名,就無法進行原始的NSInvocation,而無需修改C語言以支持將數組轉換為VARARGS,而objc_msgSend()
及其表親將不允許這樣做。 即使可以解決這個問題,您也需要計算參數的大小和返回類型(不是太難,但是如果您錯了,那么您錯了很多時間),並管理對__builtin_call()
的正確調用__builtin_call()
,這需要對消息發送體系結構或ffi有深入了解__builtin_call()
無論如何,它可能都歸結為__builtin_call()
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.