开发者应该经常看到单例模式这个设计模式,那什么是单例模式呢?
我们知道面向对象编程会生成很多实例,比如对于学生这个对象可能有小明、小红、小强等多个具体的学生对象,多个对象可以方便我们对不同的对象根据不同的需求进行操作。
那有没有只需要一个对象的时候呢?有的。
比如用户信息,大部分App都只允许同时只有一个用户登录,那么也就是说用户信息只会有一份,那如果我们要用对象的模式来管理用户信息,就应该保证整个App只有一个用户信息对象,否则如果存在多个的话,可能会出现改了这个对象的值,却读取了那个对象的值,造成数据不一致。
需要保证只有一个对象的情况还有很多,根据项目需求的不同一定有其用武之处。那么对于这种要求保证只有一个对象实例的设计模式,就称为单例模式,简明易懂是吧。
介绍完了单例模式是什么,现在看看怎么实现。
各个语言都有自己的单例模式,其实对于单例模式的实现,最根本的一点就在于保证全局只有一个对象实例。也就是说每次要使用的时候,如果还没创建过实例,那就创建,如果已经创建过了,那就直接获取之前创建过的。
根据上面的描述,很容易想到的一种方式是在创建的时候判断一下实例是否是 nil,如果是,表示还没创建实例,那就创建,如果不是 nil 了,说明之前已经创建过了,那就直接获取就好了。
这是一种方法,但其实判断是否为 nil 需要一定时间,虽然也不多,但是万一在这个时间之内创建了两个实例呢,尤其是在多线程的情况下。另一种更快的方式是使用一个BOOL型变量来作为判断的信号量,创建后就改变其值,每次调用时判断一下值就可以了,这会比判断 nil 要快一点,但依然不能完全保证。
那有没有可以保证绝对唯一的方法呢?有的,用 GCD 中的 dispatch_once 方法,就可以保证创建新实例的代码只执行一次,那么其创建的实例也就是全局唯一的实例了。
我们可以看看代码:
#import "Singleton.h"
@implementation Singleton
static Singleton *_instance = nil;
+ (instancetype)shareInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:NULL] init];
});
return _instance;
}
+ (id)allocWithZone:(struct _NSZone *)zone {
return [Singleton shareInstance];
}
+ (id)copyWithZone:(struct _NSZone *)zone {
return [Singleton shareInstance];
}
上面的代码就是利用 dispatch_once 方法来保证其生成新实例的代码只执行一次,可以保证多线程的唯一性。
在 alloc 时,Objective-C 会调用 allocWithZone ,通过覆写它来返回单例。复制对象的时候也是通过覆写调用的 copyWithZone 方法来达到返回唯一单例的目的。
用上面的方法,就可以创建单例了。具体的用法,纯粹看各自的发挥,可以将一些常用的操作提取出来放在头文件中供调用,这样其实就能方便的获取和操作单例的内容了。