单例模式可以保证在程序运行的过程中,一个类只有一个实例方法,而且该实例易于供外界访问。例如,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