一、什麼是單例
單例就是,一個類,每次創建都是同一個對象。也就是說只能實例化一次。
二、如何保證每次創建都是同一個對象
創建一個對象歸根揭底都會經過一個途徑,alloc方法(alloc方法會調用allocWithZone:)。因此只要保證alloc方法只會調用一次,且保證線程安全,然後把此對象放在靜態區。以後不管是創建對象還是copy對象都直接返回靜態區的對象。
三、注意點
靜態全局變量不需要考慮釋放的問題(適用於MRC),解決線程安全問題可以用互斥鎖或者GCD,後者更好。
也可設置不讓對象重復初始化,即讓初始化方法只能執行一次。
四、具體實現代碼如下
@implementation myManager
static id instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
// 1、互斥鎖
// @synchronized (self) {
// if (instance == nil)
// {
// instance = [super allocWithZone:zone];
// }
// }
// 2、GCD,只執行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == nil)
{
instance = [super allocWithZone:zone];
}
});
return instance;
}
+ (instancetype)sharedSoundTools
{
instance = [[self alloc] init];
return instance;
}
- (id)copyWithZone:(NSZone *)zone
{
return instance;
}
#pragma mark - MRC 部分代碼
- (oneway void)release
{
// 什麼都不做
}
- (instancetype)retain
{
// 本想什麼都不做,但它要返回值
return instance;
}
- (instancetype)autorelease
{
return instance;
}
- (NSUInteger)retainCount
{
// 此處防治有人不明就裡的粗暴釋放對象,比如while循環
return ULONG_MAX;
}
- (instancetype)init
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
self = [super init];
if (self)
{
self.age = 10; // 只是舉個例子,只初始化一次,可以不設置
}
});
return self;
}
@end
五、單例宏
以下代碼寫在單獨singleton.h文件裡,使用時直接包含.h頭文件。
使用方法,.h文件:singletonInterface(myManager);
.m文件:singletonImplementation(myManager);
抽取代碼如下:
#define singletonInterface(className) + (instancetype)shared##className;
#if __has_feature(objc_arc)
// 以下是ARC版本
#define singletonImplementation(className) \
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
if (instance == nil) { \
instance = [super allocWithZone:zone]; \
} \
}); \
return instance; \
} \
+ (instancetype)shared##className { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [[self alloc] init]; \
}); \
return instance; \
} \
- (id)copyWithZone:(NSZone *)zone { \
return instance; \
}
#else
// 以下是MRC版本
#define singletonImplementation(className) \
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
if (instance == nil) { \
instance = [super allocWithZone:zone]; \
} \
}); \
return instance; \
} \
+ (instancetype)shared##className { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [[self alloc] init]; \
}); \
return instance; \
} \
- (id)copyWithZone:(NSZone *)zone { \
return instance; \
} \
- (oneway void)release {} \
- (instancetype)retain {return instance;} \
- (instancetype)autorelease {return instance;} \
- (NSUInteger)retainCount {return ULONG_MAX;}
#endif
// 提示末尾一行不要有 \