2011-09-22 121 views
0

是否可以強制Objective-C調用虛擬方法的特定實例,而不是通過標準虛擬消息調度?我知道這通常是一個糟糕的想法,但我想知道如何使用Objective-C運行時來完成它。例如,給定實現 - (void)foo的A和B類,其中B是A的子類,我想用B實例調用A上的foo方法(儘管B通常會處理這條信息)。非虛擬調用Objective-C函數

我知道我可以通過將A的foo方法的內容移動到一個新方法並委託給它來實現此目的,但我想找出通過Objective-C運行時執行此操作的一些方法。

注意:就本問題而言,假定我無法更改A或B的來源,並且我仔細權衡了破壞封裝的風險。

+1

爲什麼'[超級富]'不適合您的需求?你對你想要的內容的描述正是「super」關鍵字所做的。編輯:哦,除非像bbum描述,你要調用' - 從_outside_ B'的'一個實例[A FOO]'。 –

+0

是的,我想一般稱之爲 - 不一定是從B.我不能在這一點上改變A或B的內容。 – slipheed

+0

的OP使得它聽起來就像他們對A(因此可能B)的控制,所以我有一種感覺'[超級富]'確實是最好/最簡單的答案。 – matthias

回答

4

This page是理解運行時的重要來源;一個快速的內存輔助掃描顯示標題爲「那麼發生在objc_msg發送什麼?」的部分?是一個立即回答的好地方,但整篇文章將真正幫助您瞭解發生的情況。

這裏的地方,他會查詢相應的函數指針運行時的例子,然後直接調用該函數:

//declare C function pointer 
int (computeNum *)(id,SEL,int); 

//methodForSelector is COCOA & not ObjC Runtime 
//gets the same function pointer objc_msgSend gets 
computeNum = (int (*)(id,SEL,int))[target methodForSelector:@selector(doComputeWithNum:)]; 

//execute the C function pointer returned by the runtime 
computeNum(obj,@selector(doComputeWithNum:),aNum); 
+0

這幾乎是我所需要的。鑑於B的一個實例,可我已經還給我的方法從A選擇以某種方式匹配?或者我可以問一個沒有實例的匹配選擇器的方法嗎? – slipheed

+0

instanceMethodForSelector _might_是什麼我要找的。 – slipheed

+1

'[[target superclass] instanceMethodForSelector:]'(可在NSObject文檔中找到)可以做到這一點;你需要這個而不是'-methodForSelector:',因爲'[target superclass']返回一個'Class','-methodForSelector:'不會響應。 – matthias

3

什麼馬蒂亞斯說...但是:

例如,某一類A和B實現 - (void)foo,其中B 是A的子類,我想用B 實例調用A上的foo方法(即使B通常會處理此消息)。

換句話說,你有foo第B要避免通過直接調用a的實現的實現?

顯然,如果你是B的實現者,那麼這是微不足道的;只需實施適當的邏輯以確定何時需要,並致電[super foo];

如果你不是B的實現者,那麼這是一個壞主意。它幾乎保證會導致神祕不測和/或不正當行爲。更糟糕的是,如果B實際上是系統框架的一部分,或者可能通過除更新的應用程序之外的機制進行更新,那麼您有一個定時炸彈,可能會隨時啓動任何隨機配置OS。

具體來說:

  • B的foo可以不是自包含的;它可能會在調用A的foo之前/之後執行一些操作,這些操作會設置內部狀態,以後可能需要這些內部狀態才能繼續正確操作。你正在用大錘打破封裝。

  • 直接調用實現將繞過任何KVO。除非你碰巧抓住一個派生的方法實現,那麼當派生的方法不再起作用時,你的行爲將會爆炸。

+0

我明白造成這種情況的原因很糟糕,但這更多的是爲了更好地理解運行時間而提出的一個假設性問題。 Yup; – slipheed

+0

是的;只要確保記錄顯示這是一個非常糟糕的主意。 :) – bbum