好吧,圍繞init
的簡單方法就是不寫一個讓它調用默認的NSObject實現(它只返回self
)。然後,對於你的sharedInstance
函數,定義並調用一個私有函數,在你實例化你的單例時執行類似init的工作。 (這可以避免用戶不小心重新初始化你的單身人士。)
但是,主要問題是alloc
被你的代碼的用戶調用!對於這一點,我個人推薦蘋果的首要allocWithZone:
路線...
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedInstance] retain];
}
這意味着用戶仍然會得到您的單一實例,並且如果他們分配它,他們可以用錯誤和安全,因爲這一次釋放自定義alloc在單例上執行保留。 (注意:alloc
來電allocWithZone:
,不需要單獨覆蓋。)
希望有幫助!我們如果您想了解更多的信息我知道〜
編輯:擴大答案提供範例和更多的細節 -
以Catfish_Man的回答加以考慮,這是往往並不重要的是創造一個防彈單,並相反,只需在頭文件/文檔中寫一些合理的註釋,然後輸入assert
即可。
但是,在我的情況下,我想要一個線程安全的延遲加載單例 - 也就是說,它不會被分配,直到它需要使用,而不是在應用程序啓動時自動分配。在學會了如何安全地做到這些之後,我想我可能會一路走下去。
編輯#2:我現在使用GCD的dispatch_once(...)
爲線程安全的方法分配一個單一對象只有一次的應用程序的生命週期。見Apple Docs: GCD dispatch_once。我也還是添加allocWithZone:
改寫位來自蘋果的老單實例,並添加了一個名爲singletonInit
以防止不小心被多次調用私有的init:
//Hidden/Private initialization
-(void)singletonInit
{
//your init code goes here
}
static HSCloudManager * sharedInstance = nil;
+ (HSCloudManager *) sharedManager {
static dispatch_once_t dispatchOncePredicate = 0;
dispatch_once(&dispatchOncePredicate, ^{
sharedInstance = [[super allocWithZone:NULL] init];
[sharedInstance singletonInit];//Only place you should call singletonInit
});
return sharedInstance;
}
+ (id) allocWithZone:(NSZone *)zone {
//If coder misunderstands this is a singleton, behave properly with
// ref count +1 on alloc anyway, and still return singleton!
return [[HSCloudManager sharedManager] retain];
}
HSCloudManager
子NSObject
,並且不覆蓋init
只剩下默認在NSObject
執行,根據蘋果的文件只返回自我。這意味着[[HSCloudManager alloc] init]
與[[[HSCloud Manager sharedManager] retain] self]
相同,從而使作爲延遲加載單例的困惑用戶和多線程應用程序都安全。
至於你關心用戶的子類化你的單身人士,我會說只是評論/文件清楚。任何盲目分類而不讀書的人是要求疼痛!
EDIT#3:對於ARC兼容性,只是刪除從allocWithZone:
重寫的保留部分,但保留覆蓋。
@yAaak,似乎很公平,但我覺得在無限循環中,需要消化它;)我如何確保通過私有方法創建這種單例的過程是線程安全的?其他問題:如果我遵循Apple的'allocWithZone'思想,默認NSObject的'init'會被調用(只是返回'self'或者做其他事情?)...並且用戶嘗試用'alloc'和' init'是否改變了我的屬性/ ivars初始化和NSObject再次獲得'init'的任何事情? – matm
yAak,你是對的:理智的態度你現在提出這樣的建議。我會使用你的代碼更多地使用單身人士:)我認爲你的答案相當廣泛,並考慮到Catfish_man的反對意見,所以我接受它。再次感謝! – matm
我建議dispatch_once()而不是OSAtomic *。少挑剔,同樣快或更快。 –