在開發(fā)中經(jīng)常會用到單例設計模式啸罢,目的就是為了在程序的整個生命周期內(nèi)押袍,只會創(chuàng)建一個類的實例對象甸饱,而且只要程序不被殺死联四,該實例對象就不會被釋放撑碴。保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
創(chuàng)建單例的幾種方式
方式一
傳統(tǒng)且正規(guī)的方法是把一次性代碼dispatch_once寫到allocWithZone:方法中去朝墩,目的是保證allocWithZone:方法只被調(diào)用一次醉拓,這樣一來,凡是通過[[class alloc] init]方法創(chuàng)建的實例收苏,都是指向同一個對象廉嚼。代碼如下:
+ (instancetype)shareInstance
{
ALYNetworkManager *instance = [[self alloc] init];
return instance;
}
static ALYNetworkManager *_instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
-(id)copyWithZone:(NSZone *)zone
{
// 需要遵守NSCopying協(xié)議
return _instance;
}
方式二
更加簡單的方式是把一次性代碼dispatch_once寫到獲取單例對象的類方法中去。保證只要通過這個類方法獲取的對象都是同一個實例倒戏。但是因為沒有重寫allocWithZone:方法怠噪,所以如果有開發(fā)者在外部直接調(diào)用[[class alloc] init]方法獲取實例,那么獲取的實例和通過類方法獲取的實例就不是同一個實例杜跷。這樣就不能保證實例的全局唯一性傍念。所以矫夷,尤其在多人開發(fā)中,采用這種方式存在一定的風險性憋槐。代碼如下:
+ (ALYNetworkManager *)sharedInstance {
static ALYNetworkManager *instance;
static dispatch_once_t token;
dispatch_once(&token, ^{
instance = [[ALYNetworkManager alloc]init];
});
return instance;
}
如下圖双藕,可以看到,通過shareInstance類方法獲取的實例始終是同一個阳仔,而通過[[class alloc] init] 和 shareInstance類方法獲取的實例并不是同一個:
方式三
另外忧陪,除了使用一次性代碼dispatch_once保證多線程情況下獲取的仍然是同一個對象,我們還可以使用同步鎖的方式達到這個目的近范,代碼如下:
+ (instancetype)shareInstance {
static ALYNetworkManager *instance = nil;
instance = [[ALYNetworkManager alloc] init];
return instance;
}
static ALYNetworkManager *_instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
@synchronized (self) {
if (!_instance) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
驗證多線程下獲取的是否為同一個實例嘶摊,如下圖:
方式四
當然還可以在單例的全局訪問點(類方法)中使用同步鎖,其結果和方式二是一樣的:外部都不能直接通過調(diào)用[[class alloc] init]方法來獲取單例评矩,代碼如下:
+ (instancetype)shareInstance {
static ALYNetworkManager *instance = nil;
@synchronized (self) {
if (!instance) {
instance = [[ALYNetworkManager alloc] init];
}
}
return instance;
}
單例工具類的創(chuàng)建
此處以利用dispatch_once一次性代碼 + 宏定義的方式抽取出一個通用的單例宏叶堆,其實在網(wǎng)上隨便一搜,就可以搜到一大把單例宏斥杜。
ARC\MRC判斷
#if __has_feature(objc_arc)
#else
#endif
宏抽取
#define interfaceSingleton(name) +(instancetype)share##name
#if __has_feature(objc_arc)
// ARC
#define implementationSingleton(name) \
+ (instancetype)share##name \
{ \
name *instance = [[self alloc] init]; \
return instance; \
} \
static name *_instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[super allocWithZone:zone] init]; \
}); \
return _instance; \
} \
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (id)mutableCopyWithZone:(NSZone *)zone \
{ \
return _instance; \
}
#else
// MRC
#define implementationSingleton(name) \
+ (instancetype)share##name \
{ \
name *instance = [[self alloc] init]; \
return instance; \
} \
static name *_instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[super allocWithZone:zone] init]; \
}); \
return _instance; \
} \
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (id)mutableCopyWithZone:(NSZone *)zone \
{ \
return _instance; \
} \
- (oneway void)release \
{ \
} \
- (instancetype)retain \
{ \
return _instance; \
} \
- (NSUInteger)retainCount \
{ \
return MAXFLOAT; \
}
#endif
以后如果需要創(chuàng)建單例工具類直接創(chuàng)建一個Singleton.h文件,把上面的代碼拷貝到.h文件中虱颗。在單例類(拿Person類為例)中導入這個頭文件。直接在單例類的.h文件中interfaceSingleton(name)傳入?yún)?shù)蔗喂,.m文件中implementationSingleton(name)傳入?yún)?shù)即可忘渔。
如下:
/************ALYNetworkManager.h**********/
#import <Foundation/Foundation.h>
#import "Singleton.h"
@interface ALYNetworkManager : NSObject
interfaceSingleton(ALYNetworkManager);
@end
/************ALYNetworkManager.m**********/
#import "ALYNetworkManager.h"
@implementation ALYNetworkManager
implementationSingleton(ALYNetworkManager)
@end
文/VV木公子(簡書作者)
PS:如非特別說明,所有文章均為原創(chuàng)作品缰儿,著作權歸作者所有辨萍,轉(zhuǎn)載請聯(lián)系作者獲得授權,并注明出處返弹,所有打賞均歸本人所有锈玉!
如果您是iOS開發(fā)者,或者對本篇文章感興趣义起,請關注本人拉背,后續(xù)會更新更多相關文章!敬請期待默终!