2012-06-13 90 views
0

我不認爲我想要做的事情是可能的,但這裏有人比我更狡猾,所以我想我會問反正....覆蓋基類@property,同時仍允許基類訪問它

想象一下我們有A類:

@interface A 
@property (strong) NSArray *items; 
// There'll be methods and stuff too 
@end 

現在,我們需要在更換下降該類改變一些行爲方面:

@interface B : A 
@property (strong) NSArray *items; 
// There'll be methods and stuff too 
@end 

特別,我們覆蓋th e「物品」屬性,因爲我們需要它來返回不同的東西。

這很好地運行,直到一個在B實例上調用的方法,它在A中實現並且未被B覆蓋,試圖訪問「self.items」。而不是訪問它自己的副本,它訪問B的重寫版本,從而看到意想不到的結果 - 並確實崩潰在我的真實情況下的應用程序:(

我可以通過重命名B中的屬性來解決此問題 - 但此時不再這是一個恥辱

請注意,B類可以通過超級訪問A的屬性版本。理想情況下,任何從A類訪問屬性也會訪問A的版本。有沒有辦法知道誰在請求它,例如?

Tim

+0

當你說「A類中的某個方法試圖訪問」時,我認爲你正在討論一個在B實例上調用的方法,該實例在A中實現,而不是由B覆蓋。是嗎? A的實例無法使用B的訪問器。 –

+2

我不認爲有可能做你想做的事。通過覆蓋子類中的變量/方法,該類的所有實例都將使用適合該類的方法,而不是調用方法所在的方法。 –

+0

喬希 - 是的,我已經更新了這個問題,以便更清楚。 – tarmes

回答

0

你可以在技術上實現你想要的,但在可怕的一輪 - 關於黑客。將這類事情置於自己的生產代碼中,如果一切崩潰,不要期待任何同情。

請勿將B作爲A的一個子類,使其僅屬於具有A的類。在B上實現這些方法,無論如何您都可以在子類中替換這些方法。要處理items,請確保BsetItems:A進行適當的相應調用 - 事實上,對於您覆蓋的所有方法而言,您希望也可以與A進行通信。

然後創建一個類C其中有BA。不要在其上執行任何操作。按照正常慣例allocinit回報(id)和執行的有點奇怪的任務:

A *instance = [[C alloc] init]; 

C只實現您的首選轉發邏輯:

@implementation C 

- (id)forwardingTargetForSelector:(SEL)aSelector 
{ 
    if([self.instanceOfB respondsToSelector:aSelector]) return self.instanceOfB; 
    return self.instanceOfA. 
} 

@end 

現在每個引用A使得以self是引用A的實例而不是子類。儘管如此,在系統中您有一個B的實例,並且它將通過獲取A的相關實例將優先於其服務的任何消息,同時能夠推遲任何想要達到A的任何消息,從而充當它從A繼承。

通過給那些本來具有A實例的實例C的類,它們將通過您的唯一繼承邏輯而不是默認的東西。此外,由於您已在適當的位置返回(id),並且兩者都是對象,所以這是一個安全的隱式轉換,編譯器不會抱怨說您繼續調用C未實現的方法。

+0

聰明。在我的情況下,它更簡單,只需將A作爲B的一個實例來解決所有問題 - 其明顯是明顯的!感謝您的靈感,TAFetchedResultsController(在GitHub上)對您的干預現在好多了。 – tarmes

0

你的問題很混亂,但無論如何...

重寫方法/屬性不會改變它的全局;它只會改變它覆蓋的類。如果A的一個實例訪問屬性,它仍然會訪問它自己的屬性,它不會被子類的實現神奇地接管。

(順便說一句,我要提到您的類可能是非常糟糕,如果你需要這樣的行爲,設計...)

+0

對不起,我不夠清楚。我指的是在B實例上調用的方法,它在A中實現,而不是由B重寫。上述方法顯然在某些時候訪問「self.items」,並且這樣做會檢索我重寫的版本 - 我想它繼續得到它自己的代替。 A類是由Apple編寫的 - 我不能改變它:) – tarmes

+0

如果你在'B'的實例上調用它,即使這個方法只在'A'中實現,它應該總是使用'​​B'''項目對象 –

+0

是的,但我希望有一個狡猾的方法來阻止這種情況的發生,比如如果我知道A請求它,就返回A的副本。 – tarmes

0

嗯,以及覆蓋B中的屬性意味着B中的任何存取將訪問A中的新屬性.A的行爲保持不變,A中的訪問者將始終訪問A中的原始屬性。類不能也不應該意識到它的子類。

如果您希望子類繼續訪問超類屬性,則無法覆蓋它。期。

另請注意,屬性(或其訪問者)必須在接口中聲明(基本上公開),以使其副本可以在子類中直接訪問。這是必要的,因爲在Objective-C中不存在「受保護的屬性」這樣的東西。

最後我們假設你將A,B或C類的類放在一個包中,然後忘記它們的類型,只要知道所有共享的都是一個關係,那麼就可以使用動態綁定/內省來決定哪個類方法將根據它的類型被調用。