iOS單例模式(全文無(wú)恥COPY)后補(bǔ)個(gè)人錯(cuò)誤點(diǎn)評(píng)

iOS設(shè)計(jì)模式——單例模式
http://blog.csdn.net/lovefqing/article/details/8516536

單例模式用于當(dāng)一個(gè)類只能有一個(gè)實(shí)例的時(shí)候, 通常情況下這個(gè)“單例”代表的是某一個(gè)物理設(shè)備比如打印機(jī),或是某種不可以有多個(gè)實(shí)例同時(shí)存在的虛擬資源或是系統(tǒng)屬性比如一個(gè)程序的某個(gè)引擎或是數(shù)據(jù)。用單例模式加以控制是非常有必要的。

單例模式需要達(dá)到的目的

  1. 封裝一個(gè)共享的資源

  2. 提供一個(gè)固定的實(shí)例創(chuàng)建方法

  3. 提供一個(gè)標(biāo)準(zhǔn)的實(shí)例訪問(wèn)接口

單例模式的創(chuàng)建
本文以創(chuàng)建一個(gè)MySingletonClass的單例模式為例。首先,我們需要定義一個(gè)類MySingletonClass.

[cpp] view plain copy
@interface MySingletonClass:NSObject {

}

并且為其添加一個(gè)類方法(注意,這里不是實(shí)例方法)+(id)sharedInstance;一個(gè)基本的實(shí)現(xiàn)寫(xiě)法如下:

[cpp] view plain copy
static MySingletonClass *sharedCLDelegate = nil;
+(MySingletonClass *)sharedInstance{
@synchronized(self) {
if(sharedCLDelegate == nil) {
[[[self class] alloc] init]; // assignment not done here
}
}
return sharedCLDelegate;
}
在上面的代碼中(用到了關(guān)鍵字@synchronized是為了保證我們的單例的線程級(jí)別的安全,可以適用于多線程模式下。)static變量sharedCLDelegate用于存儲(chǔ)一個(gè)單例的指針,并且強(qiáng)制所有對(duì)該變量的訪問(wèn)都必須通過(guò)類方法 +(id)sharedInstance,在對(duì) +(id)sharedInstance第一次調(diào)用時(shí)候完成實(shí)例的創(chuàng)建。這里值得留意一下的是,上面代碼中用的是[[selfclass] alloc],而不是 [MySingletonClass alloc],一般情況下這兩種寫(xiě)法產(chǎn)生同樣的效果,但是這里這樣做是為了更好的利用OOP的性質(zhì),[selfclass]可以動(dòng)態(tài)查找并確定類的類型從而便于實(shí)現(xiàn)對(duì)該類的子類化。

對(duì)實(shí)例化的控制
為了完全的實(shí)現(xiàn)實(shí)例的單態(tài)性,必須通過(guò)一定手段來(lái)避免實(shí)例多次被創(chuàng)建。+(id)sharedInstance控制了單例的創(chuàng)建和訪問(wèn),但是并不能控制其它地方的代碼通過(guò)alloc方法來(lái)創(chuàng)建更多的實(shí)例,因此我們還要重載任何一個(gè)涉及到allocation的方法,這些方法包括 +new, +alloc,+allocWithZone:, -copyWithZone:, 以及 -mutableCopyWithZone: 另外,+(id)sharedInstance也需要稍作修改。

[cpp] view plain copy

  • (id)hiddenAlloc
    {
    return [super alloc];
    }
  • (id)alloc
    {
    NSLog(@"%@: use +sharedInstance instead of +alloc", [[self class] name]);
    return nil;
    }
  • (id)new
    {
    return [self alloc];
    }

+(id)allocWithZone:(NSZone*)zone
{
return [self alloc];
}

  • (id)copyWithZone:(NSZone *)zone
    { // -copy inherited from NSObject calls -copyWithZone:
    NSLog(@"MySingletonClass: attempt to -copy may be a bug.");
    [self retain];
    return self;
    }

  • (id)mutableCopyWithZone:(NSZone *)zone
    {
    // -mutableCopy inherited from NSObject calls -mutableCopyWithZone:
    return [self copyWithZone:zone];
    }

+(id)sharedInstance修改如下:

  • (MySingletonClass *)sharedInstance {
    @synchronized(self) {
    if (sharedCLDelegate == nil) {
    [[[self class] hiddenAlloc] init]; // assignment not done here
    }
    }
    return sharedCLDelegate;
    }
    如果不考慮類的子類化,+hiddenAlloc這個(gè)方法可以省略。由于我們是用[selfclass]來(lái)實(shí)現(xiàn)類型的動(dòng)態(tài)識(shí)別,用[[selfclass] hiddenAlloc]可以避免調(diào)用到被重載過(guò)的alloc方法。此外,hiddenAlloc也為可能的子類化提供了一個(gè)調(diào)用原始alloc方法的機(jī)會(huì)。上面重載過(guò)的alloc方法只是給出一個(gè)log信息并且返回nil。Copying方法里只是簡(jiǎn)單的增加了retain的計(jì)數(shù)并沒(méi)有返回一個(gè)新的實(shí)例。這也正體現(xiàn)了單例模式的性質(zhì),因?yàn)榧夹g(shù)上來(lái)講,拷貝一個(gè)單例是錯(cuò)誤的(因?yàn)槭恰皢卫保┧栽赾opyWithZone方法中我們給出了一個(gè)錯(cuò)誤信息,當(dāng)然也可以扔出一個(gè)exception。

單例的銷毀
通常我們?cè)? -(void)applicationWillTerminate:(UIApplication *)application方法中調(diào)用如下方法:

[cpp] view plain copy

  • (void)attemptDealloc
    {
    if ([sharedCLDelegate retainCount] != 1)
    return;

    [sharedCLDelegate release];
    myInstance = nil;
    }

值得注意的是,上面這個(gè)attemptDealloc方法顧名思義,只是試圖釋放掉這個(gè)單例。如果retain的計(jì)數(shù)不為1,說(shuō)明還有其他地方對(duì)該單例發(fā)送過(guò)retain消息。考慮到一個(gè)單例模式的生存周期是整個(gè)程序結(jié)束為止。所以,在程序的任何一個(gè)地方都沒(méi)有必要向這個(gè)單例發(fā)送retain消息,即便是對(duì)這個(gè)單例有引用。而是調(diào)用sharedInstance方法來(lái)引用這個(gè)單例,這樣做是安全的,也是合乎單例模式的技術(shù)含義的。

iOS中的單例模式應(yīng)用
iOS中好幾個(gè)類都是采用了單例模式,比如NSApplication, NSFontManager, NSDocumentController,NSHelpManager, NSNull,NSProcessInfo, NSScriptExecutionContext, NSUserDefaults.

如果本文有任何錯(cuò)誤之處,歡迎拍磚指正,共同進(jìn)步, 謝謝!

個(gè)人錯(cuò)解:
需要寫(xiě)了+shareinstance;但忽略了,alloc.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容