2010-03-09 76 views
3

我正在尋找單身人士,我很好奇正確的方式來做的alloc,從看文檔,書籍&網絡似乎有幾個使用的方法。正確的方式來分配共享實例(單身人士)?

M1:

static ReactorClass *sharedReactor = nil; 
+(ReactorClass *)sharedInstance { 
    if(sharedReactor == nil) { 
     sharedReactor == [[ReactorClass alloc] init]; 
    } 
    return sharedReactor; 
} 

M2:

static ReactorClass *sharedReactor = nil; 
+(ReactorClass *)sharedInstance { 
    if(sharedReactor == nil) { 
     sharedReactor == [[super allocWithZone:NULL] init]; 
    } 
    return sharedReactor; 
} 

M3:

static ReactorClass *sharedReactor = nil; 
+(ReactorClass *)sharedInstance { 
    if(sharedReactor == nil) { 
     sharedReactor == [[[self class] alloc] init]; 
    } 
    return sharedReactor; 
} 

許多感謝...

加里

回答

2

在這種情況下使用[self class]實際上是一種浪費 - 除非您涉及子類,否則M1和M3並沒有真正的不同,實際情況是其餘的實現不符合它。

考慮,如果你創建ReactorClass的這樣的一個子類,會發生什麼:

@interface MyReactorClass : ReactorClass {} 
@end 
@implementation MyReactorClass 
@end 

如果你調用[MyReactorClass sharedInstance]你可以看到,從單一的靜態變量sharedReactor其讀數。這就好,如果你只創建一個子類,但你需要非常清楚這一點,並且你調用的任何第三方庫都不會爲它們創建的單例使用相同的基類,但你不知道。如果像Mark建議的那樣,將M3代碼複製到你的子類中,它會更好地工作,但是你需要問自己「爲什麼我要這樣做?」 - 你沒有什麼好處,完全可以編寫代碼,而不是依賴超類的實現細節。

爲了做到這一點,你需要保留一個靜態字典(在基類的初始化過程中創建),並將條目插入到您正在創建的單例的實際類中。

擔心是否重寫alloc或allocWithZone:再次是子類化的事情,但實際上,任何從singleton超類繼承並隨後使用其分配方法的人都應該得到不良行爲。如果你想編寫完美的單例基類,你應該創建和DOCUMENT被調用的其他方法,這樣子類可以解決他們可能想到的任何問題,而不會干擾你的基礎結構。

就個人而言,我的單身拋出異常出所有方法開始init和做他們真正的初​​始化在未知方法(確定,它被稱爲_init) - 它保證人們濫用單例類沒有得到意外的行爲。

這真的歸結爲「你相信你的子分類器多少錢」。如果你認爲他是個傻瓜,你需要重寫諸如釋放,保留等等的東西。如果你認爲他遵循了內存管理規則,那麼你可以將這些東西放在一邊,因爲它們只會起作用。在他們的示例代碼中,Apple在這方面確實有點愚蠢;他們有點偏執,但遠不能防蠢。

1

如果你把M3在ReactorClass的實現,那麼它是一樣的M1分配和返回ReactorClass。然而,M3可以放入ReactorClass的子類的實現中,然後返回一個指向該子類的對象的指針。

M2總是返回它是在執行超

3

我傾向於他們這樣寫:

+ (id)sharedFoo 
{ 
    static Foo *_sharedFoo; 

    if (_sharedFoo == nil) 
    { 
     _sharedFoo = [[self alloc] init]; 
    } 

    return _sharedFoo; 
} 

但是,請注意,上面的代碼不是線程安全的。如果您需要一個線程安全的實現,Chris Hanson has a good suggestion,它將在+initialize的重寫實現中創建實例。

+0

+1 for + initialize implementation – 2010-03-09 22:38:10