单例模式可以保证在程序运行的过程中,一个类只有一个实例方法,而且该实例易于供外界访问。例如,oc中的 UIApplication 可以通过 [UIApplication sharedApplication] 方法开速实例化一个UIApplication对象,而且在整个项目中仅实例化一份,即只有一个内存地址。
单例模式可以分为两类:(1)懒汉式,第一次用到这个单例对象的时候,再创建;(2)饿汉式,一进入程序就创建一个单例对象。在实际上一般都是“懒汉式”的单例模式,因为当项目中的单例对象较多时,如果使用“饿汉式”单例模式,会导致程序在一启动就加载单例对象,或许项目中的很多单例一开始更不用不到,这样就消耗了不必要的内存。所以,一般选取“懒汉式”的单例模式,这样在需要的时候,再创建单例对象。
实现单例对象步骤可以归纳为:
(1)提供全局变量;
(2)重写allocWithZone方法,(这是alloc底层调用的方法)
(3)提供类方法sharedClassName(其中ClassName为对象的名称),方便其他开发人员快速调用。
(4)重写copyWithZone方法。
如果是非ARC环境,基于上述步骤还要重写retain、retainCount、autorelease和release方法。
实现单例对象可以采用两种方式:一种是互斥锁访问,一种是GCD实现。
互斥锁实现单例模式:
static id _instance;
//这里的static修饰全局变量,使得全局变量的作用域仅限于当前文件内,保证安全
//重写allocWithZone方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
if (_instance == nil) {//保证只加一次锁,方式重复加锁
@synchronized(self) {//加锁,多线程安全
if (_instance == nil) {//防止创建多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
//实现外部调用的shared方法
+ (instancetype)sharedMusicTool{
if (_instance == nil) {
@synchronized(self) {
if (_instance == nil) {
_instance = [[self alloc] init];
}
}
}
return _instance;
}
//实现copyWithZone方法
- (id)copyWithZone:(NSZone *)zone{
return _instance;
}
//非ARC要实现
- (oneway void)release{
}
- (instancetype)retain{
return self;
}
- (NSUInteger)retainCount{
return 1;
}
- (instancetype)autorelease{
return self;
}
GCD实现单例模式:
static id _instance;
//这里的static修饰全局变量,使得全局变量的作用域仅限于当前文件内,保证安全
//重写allocWithZone方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{//代码仅被执行一次
_instance = [super allocWithZone:zone];
});
return _instance;
}
//实现外部调用的shared方法
+ (instancetype)sharedMusicTool{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{//代码仅被执行一次
_instance = [[self alloc] init];
});
return _instance;
}
//实现copyWithZone方法
- (id)copyWithZone:(NSZone *)zone{
return _instance;
}
//非ARC要实现
- (oneway void)release{
}
- (instancetype)retain{
return self;
}
- (NSUInteger)retainCount{
return 1;
}
- (instancetype)autorelease{
return self;
}
每次实现都用这段代码实现单例对象时,代码重复率高,因此定义一个专门实现单例对象的宏,其他单例对象直接调用单例的宏定义即可,简化了代码。宏定义为:
//.h文件
#define XCSingleModelH(name) + (instancetype)shared##name;
//.m文件
//ARC环境
#if __has_feature(objc_arc)
//ARC环境
#define XCSingleModelM(name) \
static id _instance; \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)shared##name{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[self alloc] init]; \
}); \
return _instance; \
} \
\
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
}
#else
//MRC环境,非ARC环境
#define XCSingleModelM(name) \
static id _instance; \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)shared##name{ \
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 self; \
} \
\
- (NSUInteger)retainCount{ \
return 1; \
} \
\
- (instancetype)autorelease{ \
return self; \
}
#endif
当定义一个单例对象的时候,可以引入宏定义:
.h文件:
#import <Foundation/Foundation.h>
#import "<span style="font-family: Arial, Helvetica, sans-serif;">SingleHod</span>.h"
@interface ClassName : NSObject
SingleHod(ClassName);
@end
.m文件:
<pre name="code" class="objc">#import "ClassName.h"
#import "SingleHod.h"
@implementation ClassName
SingleHod(ClassName);
@end