单例模式是一种很常见的设计模式,单例理解起来也很简单,就是不管如何访问始终只有一个实例化对象,定义全局共享的变量,如果对象是空则初始化一个对象,如果对象已经存在则使用已经实例化的对象。单例设计模式的作用是使得这个类的一个对象成为系统中的唯一实例,因此需要用一种唯一的方法去创建这个对象并返回这个对象的地址。下面有一张苹果官网的图片可以参考一下:
定义一个 Work 类,项目共享同一个工作处理类,定义一个静态变量,一个实例方法:
static Work *sharedWorkObj = nil;
+ (Work *)sharedWork{
if (!sharedWorkObj) {
sharedWorkObj=[[Work alloc]init];
}
return sharedWorkObj;
}
执行以下代码,最后发现两个实例对象 work 和workNext 地址是一样的:
Work *work = [Work sharedWork];
Work *workNext = [Work sharedWork];
NSLog(@"共享地址:%p - 共享地址:%p",work,workNext);
如果每次都遵守规则调用 sharedWork 方法,单例模式算是完成了,但是对象是可以实例化的,看一段下面的代码:
Work *work = [Work sharedWork];
Work *workInit = [[Work alloc] init];
NSLog(@"共享地址:%p-实例地址:%p",work,workInit);
work 和 workInit 的地址是不一样,这个时候我们需要动手改造以下改成的方法,让实例化对象的出来的地址也是一样的,这个时候需要重写 allocWithZone 方法:
+ (Work *)sharedWork{
if (!sharedWorkObj) {
sharedWorkObj=[[super allocWithZone:NULL] init];
}
return sharedWorkObj;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
return [self sharedWork];
}
如果对象拷贝的时候也需要是同一对象的话,可以加一个方法:
+ (id)copyWithZone:(struct _NSZone *)zone{
return [self sharedWork];
}
如果为了确保多线程情况下,仍然确保实体的唯一性,这个时候可以加上 @synchronized,@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对 self 对象进行修改。这个是objective-c 的一个锁定令牌,防止 self 对象在同一时间内被其它线程访问,起到线程的保护作用。单例模式或者操作类的 static 变量中使用比较多。当两个并发线程访问同一个对象 @synchronized(self) 同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
+ (Work *)sharedWork{
@synchronized(self){
if (!sharedWorkObj) {
sharedWorkObj=[[Work alloc] init];
}
}
return sharedWorkObj;
}
苹果 Mac OS 10.6 和 iOS4.0 后引入了 GCD,利用 GCD(Grand Central Dispatch)和ARC(Automatic Reference Counting)实现单例,这个时候我们可以通过 dispatch_once 简单的实现,代码如下:
+ (instancetype)sharedInstance
{
static Work *sharedWorkObj = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedWorkObj =[[super allocWithZone:NULL] init];
});
return sharedWorkObj;
}
Work.m中的代码:
#import "Work.h"
@implementation Work
static Work *sharedWorkObj = nil;
+ (Work *)sharedWork{
if (!sharedWorkObj) {
sharedWorkObj = [[super allocWithZone:NULL] init];
}
return sharedWorkObj;
}
+ (id)copyWithZone:(struct _NSZone *)zone{
return [self sharedWork];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
+ (instancetype)sharedInstance
{
static Work *sharedWorkObj = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedWorkObj =[[super allocWithZone:NULL] init];
});
return sharedWorkObj;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
return [self sharedInstance];
}
@end