2012-01-13 51 views
4

這是一個相當複雜的繼承層次結構,所以請耐心等待(我試圖簡化一些事情,而不是說明我正在使用的確切情況,這更加複雜): -Objective-C - 子類代理子類

假設我創建了一個UITextField的子類,名爲TextField,這是我自己定製的增強型通用文本字段。現在,爲了提供這種增強的功能,在init方法TextField中,我設置了super.delegate = self,使得來自UITextField的所有代理方法都被髮送到TextFieldTextField實現UITextFieldDelegate協議並接收這些委託方法來做一些有趣的事情。

但是,反過來,我想讓TextField擁有自己的委託。因此,我創建了一個名爲TextFieldDelegate的新協議(注意缺少UI -prefix!),並給予TextField帶有相應屬性的ivar id<TextFieldDelegate> __weak delegate,以便其他類可以接收來自TextField的委託方法。

我希望你仍然和我在一起,因爲到目前爲止我還沒有做過太複雜的事情。但是讓我們假設現在我創建了另一個自定義子類TextField,我們稱之爲PasswordTextField(在現實生活中,可能不需要創建子類來實現密碼功能,但假設有一些相當複雜的實現那需要這個)。

我們還假設我想使PasswordTextField(如TextField具有代理屬性)能夠發送一組增強的委託方法。例如,也許它可以發送一個方法passwordIsSecure,一旦密碼達到所需的複雜程度就發送該方法。現在由於這種行爲在常規TextField中找不到,我創建了一個新協議:PasswordTextFieldDelegate <TextFieldDelegate>,它定義了PasswordTextField的新委託方法,它繼承了TextField發送的所有委託方法。

問題是:如何在PasswordTextField中執行此操作?不工作的事情:

繼承

我不能簡單地從TextField繼承的委託,因爲TextField的代表只聽TextFieldDelegate而不是PasswordTextFieldDelegate,所以我無法發送方法如[delegate passwordIsSecure]因爲TextFieldDelegate沒有這樣的方法。

重寫伊娃

我可以嘗試聲明中PasswordTextField伊娃稱爲委託,但是編譯器會抱怨,這是一個重複的聲明,自然是因爲已經有所謂的代表在超伊娃,所以這不工作*。

修改超

我能回到TextField類,並重新委託同時實現TextFieldDelegatePasswordTextFieldDelegate,但這似乎凌亂,並告訴TextField,它可以發送PasswordTextFieldDelegate方法,其中當然,它不能!

我沒有試過這個,只是因爲它似乎打破了書中每一個明智的編碼規則。

總之,這樣做必須有一些方法,這樣一個類的子類可以擁有它自己的委託,它是超類委託的子委託,並且所有這些都可以很好地配合在一起,但是我可以不知道!有任何想法嗎?

(*作爲一個方面的問題,我不明白爲什麼編譯器會抱怨當PasswordTextField聲明瞭一個「重複」伊娃命名的委託,但是當TextField聲明伊娃命名委託這大概是的UITextField重複不抱怨的財產叫代表!)

+0

可能只是打在黑暗中..但不會有幫助,如果你只是重新聲明你的委託的@屬性爲ID ,並有自己的綜合?我認爲它會奏效。 mebbe生病後試一試 – govi 2012-01-13 14:02:48

回答

1

UITextField委託伊娃被命名_delegate,而不是委託。因此,爲什麼你不再在TextField中聲明它,而是在PasswordTextField中聲明它。

至於你的委託繼承問題。我不確定ObjectiveC支持你想要的。

您可能只需鍵入代理'id',而不是'id <TextFieldDelegate>'。然後,您可以重寫setDelegate並確保委託在conformsToProtocol中傳遞。但是,您將在此處丟失編譯時間檢查,只能運行檢查conformsToProtocol

+0

感謝澄清_delegate行爲。 我確實考慮過只是將類型設置爲id--我忘記將它包含在可能的解決方案列表中,但是如您所說,它會丟失編譯時檢查,所以我會認爲會有更好的解決方案? – 2012-01-13 12:57:25

+0

那麼你不能擁有兩全其美的世界(我不認爲你可以....也許有些語言更好).....我來自Java,我錯過了強大的類型安全首先。但Objective-C比Java更靈活,我可以忍受這些小怪癖 - 並享受這種語言的所有其他偉大之處。但是,如果我真的不能提供某種類型的東西,我只會使用'id'。 – bandejapaisa 2012-01-26 19:46:01

+0

我可以得到一個代碼示例嗎? – 2014-04-15 11:50:48

1

因此,那裏!工程..和管理有編譯時的警告以及..

SimpleParent.h

@protocol Parentprotocol <NSObject> 

@end 

@interface SimpleParent : NSObject { 
    id<Parentprotocol> obj; 
} 

@property (retain) id<Parentprotocol> obj; 

@end 

SimpleParent.m

#import "SimpleParent.h" 

@implementation SimpleParent 
@synthesize obj; 

@end 

SimpleChild.h

#import <Foundation/Foundation.h> 
#import "SimpleParent.h" 

@protocol SimpleChildProtocol <Parentprotocol> 


@end 

@interface SimpleChild : NSObject 

@property (assign) id<SimpleChildProtocol> obj; 

@end 

SimpleChild.m

#import "SimpleChild.h" 

@implementation SimpleChild 
@synthesize obj; 

@end 
+1

這工作,直到SimpleChild需要也繼承SimpleParent。有沒有辦法處理它,所以同時繼承類和協議的作品? – jowie 2012-09-20 11:49:41

1

這是一個相當混亂的問題,所以請原諒我,如果我錯過了這一點,但看起來你的三個不同的繼承層次都有不同的要求,每個代表都必須遵守不同的協議,那麼這是一個解決方案,將每個級別的代表作爲一個不同名稱的伊娃,並作爲一個不同的參考?

例如,您的基類將有其delegate,您決定將其分配給第一個繼承子類。這是它自己的代表,名爲level1delegate,下一級別有另一個代表,名爲level2delegate。如果該對象符合所有三種協議,您當然可以將這三種設置爲同一個對象。

基本上,沒有規定說委託必須被稱爲「委託」,所以不要爲了不打破它而撕裂自己。

+0

我想象他習慣於其他語言,可以讓你做到這一點。例如,在Java中,我可以聲明一個實例變量爲特定接口(即協議),並且在子類中,我可以重新定義實例變量爲更專用的類型(即接口的擴展)。但是,Java是強烈靜態類型 – bandejapaisa 2012-01-14 17:10:07

+0

是的,在開發Objective-C之前,我是一名Java開發人員! – 2012-01-26 16:56:15