單例的必要認(rèn)識(shí)(深刻理解)

圖片來源網(wǎng)絡(luò)

最近我面試人家,問他對(duì)單例的認(rèn)識(shí),他對(duì)單例的基本認(rèn)識(shí)、創(chuàng)建方式回答全對(duì),只有一點(diǎn)吞吞吐吐。

單例的認(rèn)識(shí)

單例模式:?jiǎn)卫J绞窃O(shè)計(jì)模式中最簡(jiǎn)單的形式之一。這一模式的目的是使得類的一個(gè)對(duì)象成為系統(tǒng)中的唯一實(shí)例
系統(tǒng)單例:
1、UIApplication(應(yīng)用程序?qū)嵗?
2、NSNotificationCenter(消息中心):
3、NSFileManager(文件管理):
4、NSUserDefaults(應(yīng)用程序設(shè)置):
5、NSURLCache(請(qǐng)求緩存):
6、NSHTTPCookieStorage(應(yīng)用程序cookies池):

1.單例模式的要點(diǎn):

顯然單例模式的要點(diǎn)有三個(gè);一是某個(gè)類只能有一個(gè)實(shí)例;二是它必須自行創(chuàng)建這個(gè)實(shí)例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。

2.單例模式的優(yōu)點(diǎn):

1.安全性和唯一性:Singleton 會(huì)阻止其他對(duì)象實(shí)例化其自己的 Singleton 對(duì)象的副本,從而確保所有對(duì)象都訪問唯一實(shí)例。單例類也可以防止他人復(fù)制(copy),保留(retain)或釋放(release)實(shí)例。如果您發(fā)現(xiàn)需要,您可以創(chuàng)建自己的單例。例如,如果您有一個(gè)類為應(yīng)用程序中的其他對(duì)象提供聲音,則可以將其設(shè)為單例。

2.靈活性:因?yàn)轭惪刂屏藢?shí)例化過程,所以類可以更加靈活修改實(shí)例化過程

創(chuàng)建步驟

1、為你的單例類聲明一個(gè)靜態(tài)的實(shí)例(聲明靜態(tài)全局變量),并且初始化它的值為nil; eg:
static TestSingleton *testSingleton = nil;
這樣,在獲取實(shí)例的方法中,只有在靜態(tài)實(shí)例為nil的時(shí)候,產(chǎn)生一個(gè)你的類的實(shí)例,這個(gè)實(shí)例通常被稱為共享的實(shí)例;
2、重寫allocWithZone方法,用于確定:不能夠使用其他的方法創(chuàng)建我們類的實(shí)例,限制用戶只能通過獲取實(shí)例的方法得到這個(gè)類的實(shí)例。所以我們?cè)赼llocWithZone方法中直接返回共享的類實(shí)例;
3、寫+(instancetype)shareSingleton的函數(shù)體

創(chuàng)建方法

一、傳統(tǒng)方法

+(instancetype)shareSingleton{ 
static Singleton *singleton = nil; 
if (singleton == nil){ 
singleton = [[self alloc] init]; 
} 
return singleton; 
}

二、推薦方法(GCD)

+(instancetype)shareSingleton{ 
static Singleton *singleton = nil; 
//給單例加一個(gè)線程鎖 
static dispatch_once_t onceToken; 
dispatch_once(&onceToken, ^{ 
singleton = [[Singleton alloc] init]; 
}); 
return singleton;

三、線程加鎖方法(不推薦使用)

+(instancetype)shareSingleton{ 
static Singleton *singleton = nil; 
@synchronized(self) { 
singleton = [[Singleton alloc] init]; 
} 
return singleton; 
}

注:“線程加鎖方法”這樣性能不是很好,因?yàn)槊看握{(diào)用+ (instancetype)sharedSingleton函數(shù)都會(huì)付出取鎖的代價(jià)

吞吞吐吐:

但我問他,這樣寫的話是保證了線程安全,但通過自帶的<code>alloc</code>或者<code>new</code>來進(jìn)行實(shí)例化,還是不能保證該對(duì)象只被創(chuàng)建一次,如何避免呢?他就回答不上了,其實(shí)很簡(jiǎn)單:

  • .h頭文件:
@interface TestSingleton : NSObject
@property (nonatomic, copy)NSString *testStr;
+ (TestSingleton *)shareinstance;

@end
  • .m文件:
+ (TestSingleton *)shareinstance {
    static TestSingleton  *testSingleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
//testSingleton = [self singletonAlloc]; //后面使用該創(chuàng)建方法  
testSingleton = [self new];//[[self alloc]init];
    });
    return testSingleton;
}

//我們需要重載<code>alloc、new</code>方法

+ (instancetype)singletonAlloc
{
    return [super alloc];
}

+ (instancetype)alloc
{
//加斷言,使用alloc會(huì)蹦,并且reason提示
    NSAssert(NO, @"不要用alloc,要使用singletonAlloc方法創(chuàng)建");
    return nil;
}
+ (instancetype)new
{
    return [self alloc];
}

+ (TestSingleton *)shareinstance {
    static TestSingleton  *testSingleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    testSingleton = [[self singletonAlloc]init]; 
    });
    return testSingleton;
}

重載了alloc、allocWithZone和new方法,在alloc方法中加上斷言來提醒,讓用戶不能使用alloc創(chuàng)建實(shí)例。

擴(kuò)展一:(面試經(jīng)常問到)

普通類跟單例的區(qū)別

普通類允許調(diào)用者根據(jù)需要?jiǎng)?chuàng)建盡可能多的類的實(shí)例,而對(duì)于單例類,每個(gè)進(jìn)程只能有一個(gè)類的實(shí)例,保證了單例數(shù)據(jù)的唯一性,安全性
調(diào)用下面方法:

-(void)testSigleton
{
    /**
     *  singleton和singleton2是同一個(gè)對(duì)象;
     */
    TestSingleton *singleton = [TestSingleton shareinstance];
    TestSingleton *singleton2 = [TestSingleton shareinstance];
    
    if (singleton == singleton2) {
        NSLog(@"singleton == singleton2");
    }
    
    NSLog(@"singleton地址:%@",singleton);
    NSLog(@"singleton2地址:%@",singleton2);
}

打印如下

 SingletonTest[1598:54880] singleton == singleton2
 SingletonTest[1598:54880] singleton地址:<TestSingleton: 0x60000001e930>
 SingletonTest[1598:54880] singleton2地址:<TestSingleton: 0x60000001e930>

可以看出地址一樣,證明單例只會(huì)創(chuàng)建一個(gè)靜態(tài)變量,全局唯一

擴(kuò)展二:(宏定義單例)

作用:有時(shí)在項(xiàng)目中需要?jiǎng)?chuàng)建好多個(gè)單例,把單例的代碼定義為宏,則可以省去重復(fù)代碼,節(jié)省時(shí)間。

/**
 *  在.h文件中定義的宏,arc
 *
 *  DWSingletonH(classname, accessorMethodName) 這個(gè)是宏
 * 在外邊我們使用 “DWSingletonH(classname,   accessorMethodName)” 那么在.h文件中,定義了一個(gè)方
   法"+ (instancetype)accessorMethodName;"
 *
 */
#define DWSingletonH(classname, accessorMethodName) + (instancetype)accessorMethodName;

/**
 *  在.m文件中處理好的宏 arc
 *
 *  DWSingletonM(classname, accessorMethodName) 這個(gè)是宏,因?yàn)槭嵌嘈械臇|西,所以每行后面都有一個(gè)"\",最后一行除外
 */
#define DWSingletonM(classname, accessorMethodName) \
static classname *instance_ = nil;\
+ (instancetype)accessorMethodName{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
instance_ = [[self alloc] init];\
});\
return instance_;\
}\
+ (instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
instance_ = [super allocWithZone:zone];\
});\
return instance_;\
}\
- (id)copyWithZone:(NSZone *)zone{\
return instance_;\
}

把上面代碼用一個(gè)<code>Header File</code>文件里面,然后就可以在其他類快速創(chuàng)建單例了

  • .h頭文件:
@interface Singleton2 : NSObject
//@property double t;
DWSingletonH(Singleton2, shareInstance)
@end
  • .m文件:
@implementation Singleton2
DWSingletonM(Singleton2, shareInstance)
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 單例模式(SingletonPattern)一般被認(rèn)為是最簡(jiǎn)單、最易理解的設(shè)計(jì)模式,也因?yàn)樗暮?jiǎn)潔易懂,是項(xiàng)目中最...
    成熱了閱讀 4,545評(píng)論 4 34
  • 1 場(chǎng)景問題# 1.1 讀取配置文件的內(nèi)容## 考慮這樣一個(gè)應(yīng)用,讀取配置文件的內(nèi)容。 很多應(yīng)用項(xiàng)目,都有與應(yīng)用相...
    七寸知架構(gòu)閱讀 6,977評(píng)論 12 68
  • 前言 本文主要參考 那些年,我們一起寫過的“單例模式”。 何為單例模式? 顧名思義,單例模式就是保證一個(gè)類僅有一個(gè)...
    tandeneck閱讀 2,630評(píng)論 1 8
  • 單例:意思就是只有一個(gè)實(shí)例。單例模式確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。這個(gè)類稱為單...
    CoderZS閱讀 644評(píng)論 1 13
  • 單例一般作為:工具類 單例命名:一般情況下如果一個(gè)類是單例,那么就要提供一個(gè)類方法用于快速創(chuàng)建單例對(duì)象,而且這個(gè)類...
    甘哲157閱讀 1,830評(píng)論 0 15

友情鏈接更多精彩內(nèi)容