2016-04-11 44 views
0

這裏是初始化爲一個類的方法:除了語法之外,將初始化方法編寫爲實例還是類方法還有什麼區別嗎?

+ (instancetype)imageEditorForDocument:(ImageDocument*)imageDocument 
{ 
    ImageEditorViewController* result = nil; 
    result = [[ImageEditorViewController alloc] initWithNibName:@"ImageEditorViewController" 
                 bundle:[NSBundle mainBundle]]; 

    if (result) 
    { 
     result.imageDocument = imageDocument; 
    } 
    return result; 
} 

這裏是一個初始化的實例方法:

- (instancetype)initWithDocument:(ImageDocument *)imageDocument 
{ 
    self = [[ImageEditorViewController alloc] initWithNibName:@"ImageEditorViewController" 
                 bundle:[NSBundle mainBundle]]; 

    if(self) 
    { 
     self.imageDocument = imageDocument; 
    } 
    return self; 
} 

據我所知道的,唯一的區別是發送者沒有按」當使用類初始化程序時,需要調用alloc

但是有沒有其他原因?

此外,一個側面的問題是否有一個名稱爲初始化是一個類方法? 像NSColor

+ (NSColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_MAC(10_9); 
+1

它被稱爲工廠方法。 – rmaddy

回答

2

帶手動引用計數(MRC),所不同的是工廠方法通常被返回一個autoreleased實例,而實例方法返回一個實例,該呼叫者現在擁有。

使用自動引用計數(ARC),該差異現在對調用代碼是隱藏的。

所以唯一的區別是調用者方便,以及爲類的作者編寫可選的工廠方法稍微多些工作。

順便說一句 - 你的實例方法初始化不正確。它應該更喜歡這個(不正確的方式來設置self):

- (instancetype)initWithDocument:(ImageDocument *)imageDocument 
{ 
    self = [super initWithNibName:@"ImageEditorViewController" 
          bundle:[NSBundle mainBundle]]; 

    if(self) 
    { 
     self.imageDocument = imageDocument; 
    } 

    return self; 
} 

而鑑於此,您的工廠方法真的應該是:

+ (instancetype)imageEditorForDocument:(ImageDocument*)imageDocument 
{ 
    ImageEditorViewController* result = [[[self class] alloc] initWithDocument:imageDocument]; 

    return result; 
} 
+0

感謝rmaddy :)並哎呀我的錯誤代碼 - 我實際上只是複製粘貼工廠方法,並將其更改爲實例初始化 - 看起來像忽略了那部分。感謝您的更正^^ –

+0

請參閱我的最新更新。你的工廠方法也是錯誤的。 – rmaddy

+0

儘管我們當前的代碼中不存在實例初始值設定項。 所以你建議我創建實例初始化方法,然後改變工廠方法來調用它? –

1

是有一個主要區別。如果你實現了一個工廠方法(類方法),你可以例如選擇返回一個已經存在的對象實例(例如從某種緩存)而不是創建一個新的實例。想象一下,你有一個類Country這是昂貴的初始化。因此,寫出下列工廠方法查找緩存第一和唯一的,如果它沒有找到它創建了一個新的對象國:

+(instancetype) countryForCountryCode: (NSString *)countryCode 
{ 
    Country *country = ... // ask our "CountryCache" if we already have a cached instance of the country 
    if (!country) { 
     country = [[Country alloc] init]; 
     // Here you would also set up the new Country object, or even write a "private" initializer 
     // You would also add the new instance to the cache here 
    } 
    return country; 
} 

在另一方面,當你選擇了「傳統」的初始主叫在初始化程序被調用之前,將始終通過alloc創建一個新實例,並且您將無法返回緩存的對象。

最後,我只記得我個人使用工廠方法,每當我處理持久對象(如果不使用CoreData)。所以,如果我想從數據庫中獲得一個新對象,我通常會實現一個名爲「load」的工廠方法。要真正在數據庫中創建新記錄,我需要實現另一個名爲「create」的工廠方法。如果你在這裏使用初始化器,它會變得非常混亂。

+0

我不確定我理解這個概念聽起來是否正確,但我並不完全在那裏。什麼阻止你在實例初始化器中返回緩存對象?在調用'[super init]'之前,不能進行檢查,只是返回緩存對象(如果存在)? –

+0

阻止我的是在實例初始化器我已經「在」調用者用'alloc'創建的新實例中,實際上我需要爲'self'指定一些其他對象,這是不允許的 – Lasse

+0

@AO我編輯了我的答案,希望我的觀點現在更清晰 – Lasse

相關問題