一、单例模式的实现
1、ARC单例
1>提供一个全局静态变量,保存单例的实例,因为放在静态区,我们不需要关心释放问题,等待程序结束的时候,系统将实例与其他的静态去变量一同销毁
static id instance;
2>提供全局访问的方法通常以shared+类名,单例获取方法保证对象只被分配一次内存空间(实例化一次)
+ (instancetype)shared类名{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
3>重写allocWithZone方法,保证只给单例对象分配一次内存(实例化一次)。因为对象的实例化alloc实质上是要调用+allocWithZone:方法,只要重写该方法,基本就能实现单例
4、在实现单例的时候通常使用GCD的dispatch_once()函数来保证单例的线程安全
5、具体实现(其实什么都没有干,只是给allocWithZone加上线程安全)
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
if(!instance){
instance = [super allocWithZone:zone];
}
});
return instance;
}
6、因为copy同样能产生新的对象copyWithZone:
- (id)copyWithZone:(NSZone *)zone{
return instance;
}
2、MRC单例
处理实现ARC部分的单例需要做的事情,还得实现MRC下的内存管理相关的方法
- (instancetype)retain {
return instance;
}
- (instancetype)autorelease {
return instance;
}
//为了防止用NSLog输出retainCount可以实现retainCount方法给一个够大的数,吓死哪些细化打印retainCount的人
就像NSString一样,打印NSString的retainCount如果是64bit系统,会返回一个2^64的数ULONG_MAX,我们可以模仿
- (NSUInteger)retainCount {
return ULONG_MAX;
}
二、单例宏抽取
1、##在连接前后变量为一个变量
2、宏换行用\
3、__has_feature(objc_arc)判断是否是ARC环境
#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
// 提示末尾一行不要有 \
三、小结
单例实现(只要重写了allocWithZone方法,其余方法的重写,都直接返回我们定义好的保存单例对象的静态变量)
1、提供一个保存单例实现的静态变量
2、重写allocWithZone方法
3、提供工厂方法shared+类名
4、如果是MRC的重写retain,release,autorelease,retainCount方法
5、重写copyWithZone
6、单例宏的使用
只要传入想要实现的单例对象的类型,即可实现一个单例
7、常见的单例
UIApplication
NSNotificationCenter
NSFileManager
NSUserDefaults
四、一句话单例
自己实现单例的时候,只要提供一个静态变量用来保存单例对象;重写所有能产生对象的方法(MRC比ARC多重写内存管理的方法release,autorelease,retain,retainCount);重写必要方法的时候,只要allocWithZone,和retainCount(返回ULONG_MAX),其余方法一律返回静态变量;提供工厂方法shared+类名创建对象