一、单例概述
所谓单例就是确保在程序运行过程中只创建一个对象实例。
- 节省内存开销。如果某个对象需要被多个其它对象使用,那可以考虑使用单例,因为这样该类只使用一份内存资源。
- 使用单例,可以确保其它类只获取类的一份数据(变量值)。
- 保证在程序运行过程中,一个类只有一个实例。
- 必须能够自行创建这个实例
- 易于供外界使用。
- 在整个应用场合中,共享一份资源(只需创建初始化一次)
系统的[UIApplication sharedApplication]、[NSUserDefaults standardUserDefaults]、- 登陆界面、播放器、工具类文件下载等。
二、单例的实现
实现主要是围绕着一个目的,在内存中创建唯一一个实例。
下面两种方式都是保证通过[MKSingletonPattern shareInstance]或者[[MKSingletonPattern alloc] init]等方式创建或者copy、mutableCopy操作最后的地址是同一个,且线程安全的。
//使用static修饰全局变量主要是保证只有该文件可以使用,外界是没有办法使用的,防止外界将指针清空
//初始化一个被强指针指向的全局变量,保证在整个进程中单例对象不要释放
static MKSingletonPattern *_instance = nil;
+ (instancetype)shareInstance {
return [[self alloc] init];
}
//alloc调用此方法分配内存空间,防止外部通过alloc init方式创建对象
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
//对请求的同一块内存资源加锁
@synchronized (self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
//防止外部对单例对象copy操作产生不同实例,遵循NSCopying协议
- (id)copyWithZone:(nullable NSZone *)zone {
return _instance;
}
//防止外部对单例对象mutableCopy操作产生不同实例,遵循NSMutableCopying协议
- (id)mutableCopyWithZone:(NSZone *)zone {
return _instance;
}
外部调用和结果
MKSingletonPattern *s1 = [MKSingletonPattern shareInstance];
MKSingletonPattern *s2 = [MKSingletonPattern shareInstance];
MKSingletonPattern *s3 = [[MKSingletonPattern alloc] init];
MKSingletonPattern *s4 = [[MKSingletonPattern alloc] init];
MKSingletonPattern *s5 = [[MKSingletonPattern shareInstance] copy];
NSLog(@"\ns1--%p\ns2--%p\ns3--%p\ns4--%p\ns5--%p\n", s1, s2, s3, s4, s5);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
MKSingletonPattern *single = [MKSingletonPattern shareInstance];
MKSingletonPattern *single1 = [[MKSingletonPattern alloc] init];
NSLog(@"shareInstance=%p------single1=%p", single, single1);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
MKSingletonPattern *single = [MKSingletonPattern shareInstance];
MKSingletonPattern *single1 = [[MKSingletonPattern alloc] init];
NSLog(@"shareInstance=%p------single1=%p", single, single1);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
MKSingletonPattern *single = [MKSingletonPattern shareInstance];
MKSingletonPattern *single1 = [[MKSingletonPattern alloc] init];
NSLog(@"shareInstance=%p------single1=%p", single, single1);
});
s1--0x600001b594b0
s2--0x600001b594b0
s3--0x600001b594b0
s4--0x600001b594b0
s5--0x600001b594b0
shareInstance=0x600001b594b0------single1=0x600001b594b0
shareInstance=0x600001b594b0------single1=0x600001b594b0
shareInstance=0x600001b594b0------single1=0x600001b594b0
只需要在allocWithZone方法中添加一次性代码
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
防止调用 alloc]init]引起的错误
防止调用 new 引起的错误
防止调用 copy 引起的错误(应该不常用)
防止调用 mutableCopy 引起的错误(应该不常用)