2013-11-01 51 views
0

在init方法中,Objective C可能返回不同類的實例嗎? 我有一個類叫:MyCustomClass。我還有其他兩個不同的課程,分別叫做Class 1Class2。我試圖實現的是:當我打電話[[MyCustomClass alloc] initWithSomeParameters創建實例Class1Class2取決於某些條件。Objective-C返回不同類的實例,初始化爲

MyCustomClass.m

#import "MyCustomClass.h" 
#import "Class1.h" 
#import "Class2.h" 

-(id) initWithSomeParameters: (id) params{ 
    id myClass; 
    if (someCondition){ 
    myClass = [[Class1 alloc] initWithSomeParameters:(id) params]; 
    [myClass setSomething:something]; 
    }else{ 
    myClass = [[Class2 alloc] initWithSomeParameters:(id) params]; 
    [myClass setSomething:something]; 
    } 
    return myClass; 
} 

...後來我打電話

id myCustomClass = [[MyCustomClass alloc] initWithSomeParameters:(id) params]; 

這是一種錯誤的做法?如果是這樣,那麼正確的是什麼?

+1

可能重複[?到底什麼是所謂的 「類簇」 在Objective-C](http://stackoverflow.com/questions/1844158/what-exactly -is-a-so-called-class-cluster-in-objective-c) – 2013-11-01 13:43:01

+0

是你的MyCustomClass的'Class 1'和'Class 2'子類 – Priyatham51

+0

感謝您的快速回答!不,Class1和Class2不是MyCustomClass的子類。 Class1是UIAlertView,Class2是UIView的子類。 MyCustomClass是NSObject。 –

回答

3

其他人已經提到過這個,但調用[[MyClass alloc] init]的結果必須始終爲nil或者一種MyClass。它不必特別是MyClass的實例;它的後代之一是可能的,如NSArrayNSString。在代碼中,這個要求看起來像:

MyClass *a = [[MyClass alloc] init]; 
NSAssert((a==nil) || [a isKindOfClass:[MyClass class]], @"This must always hold true."); 

我從來沒有嘗試實現這一點,但它可能將不得不是這個樣子:

- (id)initAsSubclass:(NSString *)sublcassName 
{ 
    Class c = NSClassFromString(subclassName); 
    self = [[c alloc] init]; 
    if (self) { 
     // Do Custom Init Here 
    } 
    return self; 
} 

的關鍵是:

  • 請勿執行[super init]
  • +alloc創建一個全新的對象。
  • 將新創建的對象指定爲self
  • 如果不使用ARC,請在替換值之前執行[self autorelease]。 (如果當前正在執行代碼的對象被釋放,則可能會導致問題。-autorelease將推遲到此部分完成。)
+1

在極少數情況下,將某種代理返回到某種「MyClass」或其他行爲完全類似於「MyClass」的情況是可以的。這兩者都是高級話題,並且很少成爲技術細節,而不是對答案的批評(已經死了)。你*可以並且應該*使用'[self release]; self = new;';如果通過'super'調用,超類更好的通過'self = [super init ...];''來完成。 – bbum

+0

你的代碼的缺點是它會分配一個額外的對象,然後被丟棄。 – newacct

1

它不是一個好方法。它更好地使用一些輔助類或我們的工廠模式併爲方法提供參數。然後根據參數創建一個類的對象並返回。

在不同類的init方法中創建不同類的對象不是好方法。

編輯: 如果你想顯示UIView或UIAlertView取決於iOS版本做這樣的。

@interface AlertHelper : NSObject 
+ (id)getAlert; 
@end 

/// 
@implementation AlertHelper 
+(id)getAlert{ 
NSString *version = [[UIDevice currentDevice] systemVersion]; 
int ver = [version intValue]; 
if (ver < 7){ 
//For iOS 6 
return something; 
} 
else{ 
//for ios 7 
return something 
} 
} 
@end 
+2

如果返回的類是抽象類的「實例化」的具體類,那麼我沒有看到問題。實際上,這是蘋果用'NSString'和其他許多類所做的。它是一種工廠的obj-c變體(稱爲類集羣)。 –

+1

是的,你的權利是可以的,但這是一個例外,而不是一個規則。 最好有一些靜態方法來創建對象,而不是在init中執行此操作。如果他們不在is_a關係中。 我認爲在代碼中這樣做應該非常少見或根本沒有做。 –

+0

@BradAllred OP說「Class1」和「Class2」不是「MyCustomClass」的子類。 –

1

你應該製造某種控制器,它可以初始化正確的類。您也可以使用類方法實現相同的功能。

在genreal這個給出的實現是壞的,因爲你分配內存一次[MyCustomClass alloc]然後在-(id)initWithSomeParameters:(id)params你再次分配內存。所以,即使不同的地址也會被重新渲染,這不是蘋果的指導方針,有些蘋果類也有這樣的行爲,但是他們是因爲優化而做的。但這裏是錯誤的。

+0

感謝您指出兩次分配!我不確定是否可以使用上面的init方法避免這種情況,除非必須分配UIAlertView才能調用initWithTitle ... –

+0

實際上,您可以創建例如類方法或常規方法。讓我們定義類MyDesiredClassFactory和一個方法'' - (id)giveMeMyDesiredClassWithParameters:(id)params''。 基本上在這種情況下,你應該應用** Factory **設計模式。它可以是它的一個簡化版本,但是儘量保持代碼簡單,然後再減少問題。 – Vytautas

0

做的方式是這樣的:

創建的基類,如:

#import "Base.h" 
#import "Class1.h" 
#import "Class2.h" 

@implementation Base 

+ (id)classWithParams:(id)params 
{ 
    id retVal = nil;  

    if (condition_based_on_params_means_creating_class1) 
    { 
     retVal = [[Class1 alloc] initWithSomeParameters:params]; 
    } 
    else 
    { 
     retVal = [[Class2 alloc] initWithSomeParameters:params] 
    } 

    return retVal; 
} 

@end 

的Class1從基本繼承:

@interface Class1 : Base 
{ 
} 
- (id)initWithSomeParameters:(id)parameters; 
@end 

Class2中從基本繼承:

@interface Class2 : Base 
{ 
} 
- (id)initWithSomeParameters:(id)parameters; 
@end 

最終你將有:

Base* a = [Base classWithParams:yourParams]; 
+0

OP不詢問如何創建類集羣。 –

+0

這正是我目前的實施。我將這個答案標記爲可接受的答案,因爲調用一個類方法而不是init方法似乎是完成我的特定任務的唯一方法 - (Class1是一個UIAlertView)。其中一個原因是 - (void)addSubview:(UIView *)視圖不被調用。無論MyCustomClass是NSObject,都會調用@ interface UIView(UIViewHierarchy)/ - (void)addSubview:(UIView *)視圖。我會嘗試(不知道是否可能)接受@ Neal的回答,因爲它肯定回答了我問的問題。謝謝大家! –

+0

這個問題具體問到如何使'init'方法返回不同類的實例。這並沒有回答這個問題。 – newacct