簡體   English   中英

NSInvocation需要NSMethodSignature

[英]NSInvocation needing NSMethodSignature

我一直想知道NSInvocation是否需要NSMethodSignature 假設我們要編寫自己的NSInvocation,我的要求將是這樣的:

  1. 我需要一個選擇器SEL
  2. 要調用選擇器的目標對象
  3. 參數數組

然后,我將從目標和SEL獲取IMP ,並將argument作為參數傳遞。

所以,我的問題是,為什么我們需要一個NSMethodSignature來構造和使用NSInvocation

注意:我確實知道,只有一個SEL和一個目標,我們沒有此方法的參數和返回類型,但是為什么我們要關心args和return的類型呢?

C中的每種類型都有不同的大小。 (即使相同的類型在不同的系統上可能具有不同的大小,但現在我們將忽略它。) int可以具有32位或64位,具體取決於系統。 double需要64位。 char表示8位(但可能會作為常規int傳遞,具體取決於系統的傳遞約定)。 最后也是最重要的是, struct類型的大小各不相同,具體取決於其中的元素數量和大小。 沒有任何限制。 因此,無論類型如何,都不可能以相同的方式傳遞參數。 因此,調用函數如何安排參數,以及被調用函數如何解釋其參數,必須取決於函數的簽名。 (不能有類型無關的“參數數組”;數組元素的大小是多少?)編譯正常的函數調用時,編譯器會在編譯時知道簽名,並可以根據調用約定正確地安排簽名。 但是NSInvocation是用於在運行時管理調用的。 因此,它需要方法簽名的表示才能起作用。

NSInvocation可以做幾件事。 所有這些都需要了解參數的數量和類型(至少是類型的大小):

  1. 當消息發送到沒有方法的對象時,運行時將構造NSInvocation對象並將其傳遞給-forwardInvocation: NSInvocation對象包含所有已傳遞參數的副本,因為可以稍后存儲和調用它。 因此,運行時至少需要知道參數總數,以便從寄存器和/或堆棧中復制正確數量的數據(取決於調用約定中參數的排列方式)到NSInvocation對象。
  2. 當您擁有NSInvocation對象時,可以使用-getArgument:atIndex:查詢第i個參數的值。 您還可以使用-setArgument:atIndex:設置/更改第i個參數的值。 這要求它知道1)第i個參數在其數據緩沖區的何處開始; 這需要知道先前的參數有多大,以及2)第i個參數有多大,以便它可以復制正確數量的數據(如果復制的數據太少,它將具有損壞的值;如果復制的數據也太多)比如說,當您執行getArgument ,它可以覆蓋您提供給它的緩沖區;或者當您執行setArgument ,可以覆蓋其他參數)。
  3. 您可以使它執行-retainArguments ,這將使其保留對象指針類型的所有參數。 這要求它區分對象指針類型和其他類型,因此類型信息不僅必須包括大小。
  4. 您可以調用NSInvocation ,這將導致它構造並執行對該方法的調用。 這要求它至少知道要從其緩沖區復制到寄存器/堆棧中的數據量,以將所有數據放置在函數期望的位置。 這至少需要知道所有參數的組合大小,並且可能還需要知道單個參數的大小,以便可以正確找出寄存器上的參數和堆棧上的參數之間的鴻溝。
  5. 您可以使用-getReturnValue:獲得調用的返回值-getReturnValue: 這與上面的論證有類似的問題。

    • 上面沒有提到的是,返回類型也可能對調用機制產生很大的影響。 在x86和ARM(Objective-C的通用體系結構)上,當返回類型為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM