2013-07-11 52 views
1

我有以下情況: 我正在擴展UITextView control (MyTextView : UITextView)。根據運行時設備版本,我有不同的實現。所以目前我在執行MyTextView類時有很多「if-else」語句。沒有在所有構造函數中調用super的類實例化

爲了使其更容易維護,我想將它拆分到不同的類別:

MyTextViewIos5 : MyTextViewMyTextViewIos6:MyTextView

創建一個工廠函數,它會知道在運行時根據創建該子類到設備iOS版本

該解決方案完美地工作,如果我使用MyTextView作爲參數。

MyTextView* textView = [Factory createWithFrame:frame]; 

的問題時,有從MyTextView (externalTextView:MyTextView)繼承和具體方法繼承它的類開始, 其initWithFrame方法是這樣的:

- (id)initWithFrame:(CGRect)frame { 
    self = [Factory createWithFrame:frame]; 
    if (self) { 
     ... 
    } 
    return self; 
} 

與其說超級initwithFrame我的叫我的工廠。

當我打電話externalTextView具體方法,應用程序崩潰與錯誤MyTextViewIos5MyTextViewIos6不執行被調用的具體方法。

是否有使其工作一個解決方法嗎?

+0

爲什麼你不想在init方法中調用'super'? – sergio

+0

我想了一會兒,你可以通過繼承'alloc'來處理這個問題,但可能不會。 (儘管如此,這是一種「巧妙」的方式來處理您的原始問題。) –

回答

1

簡單的MyTextViewIos5MyTextViewIos6,而不是您的自定義類指定self = [Factory createWithFrame:]只有inits數據。因此,您的自定義類的方法表等不存在,這就是它崩潰的原因。

繼承的性質是,您必須繼承MyTextViewIos5MyTextViewIos6以繼承它們的功能。問題是你不會知道哪個。

我建議分離自定義類的功能集成到一個委託/協議設計。 MyTextView超類可以包含用於管理委託的代碼。

喜歡的東西:

- (void)methodCustomSubclassWouldHaveOverridden 
{ 
    [delegate handleThisForMe]; 
} 
+0

如果我知道什麼是定製類功能,這是一個很好的解決方案。 但在我的情況下,我正在構建一個外部SDK,我不能假定任何有關要使用\ inherit MyTextView類的自定義類。 – ram

+0

@ user2572953通過使用協議,您可以定義客戶端需要實施的合同。 –

+0

對不起,我的錯......我第一次沒有正確理解你的解決方案。 你是對的,把我的自定義功能放在一個委託中,並在MyTextView類中處理它。這意味着我的自定義ios5&ios6類不會是MyTextView的子類,只會實現將由其定義的協議。這種方法可以工作,但比使用繼承要優雅得多。如果我沒有其他選擇,我會使用它。 非常感謝! – ram

0

MyTextView派生必須以自己的initWithFrame方法調用[super initWithFrame],如果你定義一個類中的每一個。如果您不需要對派生類實例進行任何自定義初始化,則可以完全忽略init方法。

在一般情況下,你的工廠createWithFrame應該是這樣的:

- (MyTextView*)createWithFrame:(CGRect)frame { 

    if (<iOS6>) 
     return [[MyTextViewOS6 alloc] initWithFrame]; 
    if (<iOS5>) 
     ... 
} 

現在,如果你的派生類不需要任何特殊的初始化,您可以簡單地放過他們每個人的initWIthFrame方法(和僅在基類中定義一個)。

或者,你可以做初始化在工廠,像這樣:

- (MyTextView*)createWithFrame:(CGRect)frame { 

    if (<iOS6>) 
     MyTextViewOS6* view = [[MyTextViewOS6 alloc] initWithFrame]; 
     view.iOS6SpecificProperty = ...; 
     [view iOS6SpecificMethod:...]; 
     return view; 
    if (<iOS5>) 
     ... 
} 

你用做什麼:

self = [Factory createWithFrame:frame]; 

被分配的MyTextView一個新的實例和更換self原值。換句話說,當你這樣做:

externalTextView* view = [[externalTextView alloc] initWithFrame]; 

首先內存分配給externalTextView類型的對象;然後,該類的initWithFrame方法被調用。現在,如果initWithFrame裏面你做:

self = [Factory createWithFrame:frame]; 

你實例化廠通過一個新的對象,並指定一個指向它self(其原來指向通過的alloc創建的對象)。

希望這會有所幫助。

+0

不幸的是,就像Justin提到的那樣:「僅僅爲MyTextViewIos5或MyTextViewIos6分配自己= [Factory createWithFrame:]的數據,而不是您的自定義類,結果,您的自定義類的方法表等不存在,這就是爲什麼它崩潰」。 – ram

相關問題