2012-03-30 29 views
2

我想做一個通用代理,它接受任何類型參數的選擇器併發送RPC調用。在這種情況下,方法的簽名是未知的,因爲它可以由最終用戶任意創建。Can methodSignatureForSelector:創建一個「全部捕捉」方法簽名?

我看到方法簽名需要用於每個參數供給類型編碼。是否有一種類型編碼能夠完全表示任何東西(指針,int,其他)?否則,是否有另一種方法來實現這種效果?

回答

2

「的一種」,但不是真的...或者,至少,沒有實用。

你可以實現方法轉發協議,使無法識別的方法調用將被包裝在一個NSInvocation中,然後你可以撕開NSInvocation,但這確實是不實際的,原因很多。

首先,它只適用於相對簡單的參數類型。 C ABI是這樣的:複雜的參數 - 結構,C++對象等等 - 可以以不可思議的方式編碼在堆棧上。事實上,它們可以用沒有足夠的元數據來解碼幀的方式進行編碼。

其次,任何種類的其中具有一個關於它的非常明顯的氣味「選擇可以由用戶任意地創建」的系統的;一種「你正在以艱辛的方式去做」的氣味。 Objective-C雖然非常具有動態性,但實際上並不支持這種純粹的元對象模式。

同樣,任何這樣產生的系統將是非常脆弱的。如果「任意選擇器」碰巧是@selector(hash),會怎麼樣?

2

你能更詳細地描述這個包羅萬象的代理,它需要轉發到什麼呢?

如果您的代理只需要每封郵件轉發到一個目標,那麼它可以在其-forwardingTargetForSelector:在運行時這樣做。如果沒有(例如,您需要轉發到多個目標或進行其他複雜的操作),則需要執行-forwardInvocation:來處理它。使用-forwardInvocation:來處理呼叫需要您實施-messageSignatureForSelector:,因爲它需要獲取方法簽名才能創建調用。 (即使將它轉發給另一個對象,該對象也需要直接實施該方法,但要添加該方法以響應+resolveInstanceMethod:或使用-forwardInvocation:處理它,所有這些都需要它也具有簽名。)

方法簽名對參數和返回類型的類型進行編碼。調用需要這些信息的原因是,當這些參數被傳遞時,它們根據它們在聲明中的類型在編譯時(可能連續地)被放置在內存中。一個大的結構體參數將比int參數佔用更多的空間。 double也可能比int更大。調用需要存儲所有這些參數,並允許您通過索引訪問或更改它們。除非您知道類型(或者至少是類型的大小),否則無法找出參數在運行時是如何佈局的。

而且,傳遞機制的消息是從其他方法(他們稱之爲objc_msgSend)返回結構(他們稱之爲objc_msgSend_stret)方法不同(在某些平臺上,返回雙打使用objc_msgSend_fpret方法)。在前一種情況下,結構不是直接返回,但要寫入的位置作爲一個額外的指針參數作爲out參數傳遞。因此瞭解返回類型對於處理調用中的調用和返回值也非常重要。

即使您將調用轉發給某個其他對象,最終該對象(或某個對象向其下一行轉發)也必須以某種方式知道方法簽名。那麼爲什麼不在需要時請求該對象的簽名呢?

沒有適用於所有事情的「安全」簽名,因爲不同的類型具有不同的大小。