1.单利模式概述
单例模式是iOS常用设计模式中的一种。单例设计模式的作用是使得这个类的一个对象成为系统中的唯一实例,因此需要用一种唯一的方法去创建这个对象并返回这个对象的地址。那么,我们何时使用单例模式呢?1、类只能有一个实例,而且必须从一个为人熟知的访问点对其访问。2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。
n 单例模式的作用p 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问p 从而方便地控制了实例个数,并节约系统资源pn 单例模式的使用场合p 在整个应用程序中,共享一份资源(这份资源只需要创建初始化 1 次)pn 单例模式在 ARC\MRC 环境下的写法有所不同 , 需要编写 2 套不同的代码p 可以用宏判断是否为 ARC 环境#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif
n ARC 中,单例模式的实现p 在 .m 中保留一个全局的 static 的实例static id_instance;
p 重写allocWithZone: 方法,在这里创建唯一的实例(注意线程安全)+ (id)allocWithZone:(struct _NSZone*)zone
{
@synchronized(self) {
if (!_instance) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
p 提供 1 个类方法让外界访问唯一的实例+ (instancetype)sharedSoundTool
{
@synchronized(self) {
if (!_instance) {
_instance = [[self alloc] init];
}
}
return _instance;
}
p 实现copyWithZone: 方法- (id)copyWithZone:(struct _NSZone*)zone
{
return _instance;
}
n 非 ARC 中( MRC ),单例模式的实现 ( 比 ARC 多了几个步骤)p 实现内存管理方法- (id)retain { return self; }
- (NSUInteger)retainCount { return 1; }
- (oneway void)release{}
- (id)autorelease { return self; }
2.单利模式之懒汉模式
2.1懒汉式实例
首先创建一个project,然后创建一个HMMusicTool类来演示懒汉式#import <Foundation/Foundation.h> @interface HMMusicTool : NSObject + (instancetype)sharedMusicTool;//写这个方法共享单例对象 @end
#import "HMMusicTool.h" @implementation HMMusicTool /** static : 修饰变量 1> 修饰全局变量 * 全局变量的作用域仅限于当前文件内部(其意义是,防止该全局变量被别人修改,只有文件内部才有权利修改) 2> 修饰局部变量 : * 局部变量的生命周期 跟 全局变量 类似 * 但是不能改变作用域 * 能保证局部变量永远只初始化1次,在程序运行过程中,永远只有1份内存 */ static id _instance; //全局变量,防止该全局变量被别人修改,只有文件内部才有权利修改(永远只有一份内存) /** * 当调用alloc方法的时候,alloc方法内部会调用这个方法 */ + (id)allocWithZone:(struct _NSZone *)zone { if (_instance == nil) { // 防止频繁加锁 @synchronized(self) { //加锁防止多线程同步的时候大家都创建对象 if (_instance == nil) { // 防止创建多次 _instance = [super allocWithZone:zone]; } } } return _instance; } + (instancetype)sharedMusicTool //写这个方法共享单例对象 { if (_instance == nil) { // 防止频繁加锁 保证init方法也只调用一次 @synchronized(self) { if (_instance == nil) { // 防止创建多次 _instance = [[self alloc] init]; } } } return _instance; } //- (id)copyWithZone:(NSZone *)zone //{ // return _instance; //} @end
此时在控制器中使用这个类#import "htingViewController.h" #import"HMMusicTool.h" @interface htingViewController () @end @implementation htingViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. HMMusicTool *tool = [[HMMusicTool alloc] init]; HMMusicTool *tool2 = [[HMMusicTool alloc] init]; HMMusicTool *tool3 = [HMMusicTool sharedMusicTool]; HMMusicTool *tool4 = [HMMusicTool sharedMusicTool]; NSLog(@"%@ %@ %@ %@",tool,tool2,tool3,tool4); } @end
打印结果:单例模式[625:607] <HMMusicTool: 0x8f3d430> <HMMusicTool: 0x8f3d430> <HMMusicTool: 0x8f3d430> <HMMusicTool: 0x8f3d430>
可以发现打印结果都是同一个对象
2.2懒汉式剖析(优缺点及实现机制)
2.2.1实现机制
1⃣️当调用alloc方法的时候,alloc方法内部会调用allocWithZone:这个方法
2⃣️提供一个share方法,如上实例
2.2.2优缺点
从线程安全性上讲,不加同步的懒汉式是线程不安全的,比如,有两个线程,一个是线程A,一个是线程B,它们同时调用alloc方法,那就可能导致并发问题。如上实例 可以加锁防止多线程同步的时候大家都创建对象。
懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。
3.单例模式之恶汉模式
3.1新建一个HMSoundTool类演示恶汉模式
#import <Foundation/Foundation.h> @interface HMSoundTool : NSObject + (instancetype)sharedSoundTool; @end
// 饿汉式 #import "HMSoundTool.h" @implementation HMSoundTool static id _instance; /** * 当类加载到OC运行时环境中(内存),就会调用一次(一个类只会加载1次) */ + (void)load { _instance = [[self alloc] init]; } + (id)allocWithZone:(struct _NSZone *)zone { if (_instance == nil) { // 防止创建多次 _instance = [super allocWithZone:zone]; } return _instance; } + (instancetype)sharedSoundTool { return _instance; } @end
控制器// htingViewController.m #import "htingViewController.h" #import"HMSoundTool.h" @interface htingViewController () @end @implementation htingViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. HMSoundTool *tool1 = [HMSoundTool sharedSoundTool]; HMSoundTool *tool3 = [HMSoundTool sharedSoundTool]; HMSoundTool *tool4 = [[HMSoundTool alloc] init]; NSLog(@"%@ %@ %@ ", tool1, tool3, tool4); } @end
打印结果
饿汉模式[1968:607] <HMSoundTool: 0x8e11770> <HMSoundTool: 0x8e11770> <HMSoundTool: 0x8e11770>
3.2恶汉模式剖析(优缺点及实现机制)3.2.1实现机制
当类加载到OC运行时环境中(内存),就会调用+ (void)load一次(一个类只会加载1次)
3.2.2 优缺点
饿汉式是线程安全的,因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的。