2010-02-03 57 views
1

我想創建一個只能通過工廠方法實例化的對象。我通過拋出異常來防止init被使用(請參閱Creating a class with no init method)。但是這意味着我必須創建一個新的方法secretInit才能在工廠方法中使用。對象只能通過工廠方法初始化(Objective-c)

//Factory method 
- (URLReqs *)buildURLReq:(NSString *)location 
{ 
    URLReqs *tmp=[[URLReqs alloc] secretInit]; 
    tmp.str=location 
    return tmp; 
} 

- (id) secretInit{ 
    return [super init]; 
} 

這種方法很混亂,儘管我們可以避免在頭文件中聲明secretInit,但仍有人可以訪問它。有更好的解決方案嗎?

一個想法是嘗試直接調用URLReqs超級對象上的init,而不是創建一個函數來執行它。

+1

我認爲你的'buildURLReq:'方法應該返回'tmp',而不是'nil'。 – dreamlax 2010-02-03 00:42:20

回答

1

你不想做這種方式,但它是可能的:


#include <objc/message.h> 

@implementation MyClass 

+ (id) factoryMethodWithParameter:(NSString *) someString; 
{ 
    struct objc_super instanceSuper; 
    id myInstance = [self alloc]; 
    instanceSuper.receiver = myInstance; 
    instanceSuper.super_class = [self superclass]; 
// instanceSuper.class = [self superclass]; // use this line if the above doesn't compile 
    myInstance = objc_msgSendSuper (&instanceSuper, @selector(init)); 

    //continue on setting up myInstance's ivars . . . 
    [myInstance setVariable:someString]; 

    return myInstance; 
} 

- (id) init 
{ 
    self = [super init]; 
    if (!self) return nil; 
    [self release]; 
    [self doesNotRecogniseSelector:_cmd]; 
    return nil; 
} 

@end 

這將允許你繼續發送init消息myInstance的「超級」對象,但不會允許任何人發送initMyClass實例。

雖然這是使用在objc/*.h中聲明的標準運行時函數,但請注意,不要期望Apple保持此運行時API的一致性。

+0

爲什麼我不想使用這種方法? – Casebash 2010-02-03 05:54:47

+0

我不知道爲什麼我告訴你不要使用它。 。 。 – dreamlax 2010-02-03 05:59:25

+0

哦!現在找到了我。我不會推薦它,因爲這是針對Apple運行時的。如果通過某種奇蹟「GNUstep」變得可以忍受或者可以選擇其他運行時,那麼這種方法可能不適用於那些運行時。我假設你的目標是Mac OS X和/或iPhone(我不確定這是否適用於iPhone),但由於你只標記了你的問題'objective-c',我想留下一個警告。然後,我忘了我正在寫什麼,並在我的回答結束時部分完成了我的想法。 – dreamlax 2010-02-03 06:16:54

0

解決方案是在您的對象上使用一個類別來隱藏祕密初始化方法。

Private Methods through categories

什麼目標,你想實現什麼?可能有比這更好的解決方案。

+1

這實際上並不隱藏該方法,而不是聲明它。它只是允許類中的其他方法知道它的存在,所以你不會得到編譯器警告。 – Casebash 2010-02-03 00:38:45

0

它只在頭文件中引用它時纔會公開它。

不,等等。我應該說另一種方式。沒有更好的方法來隱藏它,而不是在頭文件中聲明它。 Objective-C中不存在私有方法。