本文将从四个方面对iOS开发中的单例设计模式进行讲解:
一、什么是单例设计模式
二、我们为什么要用单例设计模式
三、单例设计模式的基本用法
四、自定义单例设计模式代码的封装
一、什么是单例设计模式
所谓单例,即是单个的实例化对象,保证一个类有且仅有一个实例。通常情况下,当我们对一个类实例化时(如:alloc、new等),并不能保证每次实例化的对象是唯一的实例。那么为了保证该类可在多次实例化的过程中保证内存地址不变,就需要引入单例设计模式。
二、我们为什么要用单例设计模式
1、Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例,如手机中有多个音乐播放器,但需要为用户播放最后打开的播放器中的音乐,为提高用户体验,这种播放工具类就需要用单例来实现。
2、可提高线程安全,在实例化单例时我们用到了一个dispatch_once函数
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
该函数在整个程序的声明周期中,仅执行一次某一个block对象,系统已经帮我们加了锁,所以在多个线程抢夺同一资源的时候,他也是安全的
三、单例设计模式的基本用法
通常情况下,一般的单例设计模式只需要重写两个方法即可,当然需要用来实例化对象的share或standard的类方法是必要的。
+ (id)allocWithZone:(NSZone *)zone; // IOS9.0之后不需要引入NSCopying对copyWithZone方法重写也不会报错 - (id)copyWithZone:(NSZone *)zone;
实现单例的类方法:
static id _instance; + (instancetype)shareAudioPlayer { /** 一次性执行 dispatch_once是安全的,系统已经帮我们加了锁,所以在多个线程抢夺同一资源的时候,他也是安全的 */ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"---once---"); _instance = [[self alloc] init]; }); return _instance; }
对以上两个方法的重写
+ (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone { return _instance; }
单例设计模式在ARC与非ARC下的内部机制后有一些不同,下面我们分别就两种内存管理模式对单例设计模式进行说明。
如果在ARC下,上面的代码便足够实现单例设计模式,以下代码不需重写。
如果在MRC下,则在重写以上两个方法的基础上,还要对下面的四个方法进行重写:
- (id)retain; - (NSUInteger)retainCount; - (void)release; - (id)autorelease;
// MRC下还要重写以下方法 - (oneway void)release {} - (instancetype)retain {return _instance;} - (instancetype)autorelease {return _instance;} - (NSUInteger)retainCount {return 1;}
以上即为单例设计模式在ARC或MRC下的用法。如果需要同时兼容MRC或ARC就需要对缩写代码进行判断,我们一般用条件编译来进行判断:
#if __has_feature(objc_arc) // ARC NSLog(@"MRC下插入ARC代码也是可以的,在MRC下也不会报错,但不会被执行"); #else // MRC NSLog(@"ARC下插入MRC代码也是可以的,在ARC下也不会报错,但不会被执行"); #endif
四、自定义单例设计模式代码的封装
在我们工作过程中,如果需要自定义单例设计模式,以上代码难免会重复编写,为了提高工作效率,可考虑将代码进行封装
singleton_h(DBTool) singleton_m(DBTool) /** 单例抽取成宏,只需要改两个部分,一个是.h文件里面的内容,一个是.m文件里面的内容 宏里面拼接参数用两个 ## */ // .h文件单独抽取 #define singleton_h(name) + (instancetype)share##name; #if __has_feature(objc_arc) // ARC环境下 #define singleton_m(name) static id _instance; + (instancetype)share##name { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone { return _instance; } #else // 非ARC环境下(MRC) #define singleton_m(name) static id _instance; + (instancetype)share##name { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone { return _instance; } - (oneway void)release {} - (instancetype)retain {return _instance;} - (instancetype)autorelease {return _instance;} - (NSUInteger)retainCount {return 1;} #endif
如果本文有任何错误之处,欢迎拍砖指正,共同进步, 谢谢!