2009-12-16 70 views
1

我遇到過一個與Objective-C中的類繼承有關的奇怪場景。Objective-C繼承方法匹配

比方說,我有三個類A,B和C,從基類X.級別A繼承,B和X的構造函數:

- (id)InitWithString:(NSString*)someString andDelegate:(id<SomeProtocol>)aDelegate 

唯一的區別是,每類使用不同的協議的代表。

會發生什麼情況,對於A和B,編譯器會嘗試使用C中的方法。警告通知我C類構造函數所需的協議未由提供的委託實現。委託本身沒有任何問題,因爲每個類都有一個委託,它爲類自己的構造函數實現正確的協議。在運行時一切正常,併爲所有類調用正確的函數。

我試過讓構造函數返回A *,B *或C *而不是匿名ID,儘管這仍然不能解決問題。

的作品正在鑄造到正確的類這樣的唯一的事情:

instanceOfA = [(A*)[A alloc] InitWithString:@"" andDelegate:aDelegate]; 

這似乎是多餘的和不必要的。我可能在這裏丟失了一些明顯的東西

+1

永遠不要用最初的大寫字母來命名方法,這是一種令人憎惡的做法。你也不應該在名字中使用*和*。在C#中名稱'InitWithStringAndDelegate()'是好的,在Objective-C中它應該是'initWithString:delegate:'。 – PeyloW 2009-12-16 15:52:24

+0

是的,使用「和」通常是一個壞主意,因爲如果添加其他參數,則必須更改它。最初的資本主要是品味和習慣的問題。我覺得沒有義務遵循蘋果的慣例,特別是因爲這有助於我輕鬆地在一個Cocoa類的子類中識別我自己的方法。然而,這是所有題外話:) – 2009-12-16 16:06:51

回答

1

我不確定這些情況下分析儀的實際有多聰明,並且懷疑您僅僅是遇到了其中一個限制。

您正在觀察的是編譯器將對象視爲id並選取與簽名匹配的第一個方法。嘗試移動包括你的類在內的順序,你會發現它總是選擇首先定義的選擇器。

一種方法來解決這個問題是初始化分兩步類:

ClassA *test = [ClassA alloc]; 
test = [test initWithString:@"" andDelegate:delegate]; 

在這種情況下,分析儀測試知道是類型ClassA的,並挑選合適的選擇。看起來並不那麼聰明,以至於不知道什麼類型的中介對象不是分配給變量的,而是總是假定它們是id

+0

這絕對正確。我敢肯定,我的3個班級中只有2個班級發出警告的事實只與包含訂單有關。你的解決方案分裂初始化也適用,雖然這似乎仍然過分。 – 2009-12-16 15:47:05

+0

一個類的方法也可以,但我沒有測試: 'ClassA * test = [[ClassA classAWithString:@「」andDelegate:delegate] retain]' 它有相同的結果,但只有一行。 – Adrian 2009-12-22 15:26:47

1

問題在於聲明瞭定義指定類型參數的方法。

您應該將聲明儘可能通用爲對作爲最後一個參數傳遞的對象的所有類都有效。 如果所有的協議都是從父協議繼承的,那麼你可以聲明該方法爲- (id)initWithString:(NSString*)someString andDelegate:(id<ParentProtocol>)aDelegate;不同的是,您可以使用更通用的定義- (id)initWithString:(NSString*)someString andDelegate:(id)aDelegate

+0

那麼在這種情況下,我失去了在我的初始化中強制執行特定協議的選項。我看不到這背後的邏輯。由於我被允許需要一個特定類型的參數NSString *而不是NSObject *或id,爲什麼我不能決定需要id ? 爲了澄清,我的代表不從其他代表繼承。 問題陳述中還有一個錯誤。我的基類X有一個不同的初始化程序,並且對代表一無所知。 – 2009-12-16 15:41:16

+0

使用的協議有一些共同的方法嗎? – kiamlaluno 2009-12-16 16:12:07

+0

它們沒有共同的方法 – 2009-12-16 16:18:41