创建"全世界最简单"の单例
来源:互联网 发布:java 线程池 状态 编辑:程序博客网 时间:2024/05/21 17:53
知识点
- 1、什么是单例
- 2、单例的好处
- 3、单例创建方式
- 4、封装”单例的创建”
- 5、使用单例的封装实现单例
- 6、使用单例
1、What’s 单例 ?
顾名思义,单例就是一个类只有一个实例对象。确保在程序过程中,无论创建多少次对象,该对象都是同一个实例,都指向同一块存储空空间。在设计模式中单例模式也是很常用的模式。
单例模式的三个要点
- 该类只能有一个实例;
- 它必须自行创建这个实例;
- 必须向外界提供这个实例供调用者调访问。
2、Benefit of 单例
- 可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于供外界访问
- 方便的控制了实例个数,并且大大节约系统资源
单例模式的使用场合:在整个应用程序中,共享一份资源(这份资源只需要创建初始化一次)
3、The ways to create 单例
创建方式
a) 利用手动添加线程锁
@synchronized
控制
首先要在类中申明一个私有的静态实例,保证该类被循环引用,这样单例才会一直存在不会被释放。static id _instance;
要想实例单例,就必须控制类的构造方法,因此重写
allocWithZone
方法。+ (instancetype)allocWithZone:(struct _NSZone *)zone { @synchronized (self) { if(!_instance) { _instance = [super allocWithZone:zone]; } }return _instance;}
同理,要达到实现单例,按照苹果提供的
[UIApplication sharedApplication]
方式获取单例,需要提供一个sharedInstance的类方法去访问单例。因此需要在类的.h文件中声明工厂方法,并在.m文件中实现。+ (instancetype)sharedInstance;
+ (instancetype)sharedCar {@synchronized (self) { if(!_instance) { _instance = [[self alloc] init]; }} return _instance;}
当然,有时候我们会用到一个实现了
NSCopying
的copy
对象方法,在单例中应该重写该方法,使得赋值的实例仍然是唯一的实例。- (id)copyWithZone:(NSZone *)zone { return _instance;}
b) 通过利用
GCD
中的dispatch_once
方法控制实例个数
和用线程同步锁一样的道理,要想达到单例的效果,必须控制外界创建实例的方法,而GCD的方式也不例外,只是在控制的方式上利用用dispatch_once
在程序运行过程中只会执行一次
的特性实现,并且dispatch_once
方法是线程安全的。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; }
4、封装”单例的创建”
从上面的代码我们可以看出,要想实现一个单例是很容易的。同时也可以看出实现单例的代码都是差不多一样的,除了可能在类的工厂方法的名字可能采用instance***
以为,其余的代码都是一模一样,而这样的代码重复工作量,在我们进行开发的过程中是没有多大意思并且花费时间,因此可以借用宏的特性将单例的实现进行封装,只要每次在.h文件中引入宏,并且调用宏的方法就可以实现单例。那么我不啰嗦了,直接上代码。
1. 首先需要创建一个.h文件MRSingleton.h
(当然该文件名可以根据个人喜好取名),在.h文件中进行宏的定义。
// .h 文件中需要声明的方法宏定义 #define MRSingletonH(name) + (instancetype)shared##name; // .m 文件中需要的方法宏定义 #define MRSingletonM(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;\ }
注意!!!
需要特别注意的是上面的宏定义中的\
是一定不能获缺的,因为编译器在检测宏时默认只会认为define所在一行才是宏的定义内容,因此只会将所在行的代码进行宏的替换,\
的的作用就是告诉编译器后面一行的内容仍然是宏需要替换的代码。
5、使用单例的封装实现单例
1 在声明文件.h文件中导入宏定义文件
MRSingleton.h
#impport "MRSingleton.h"
- 2 在.h文件中调用宏的方法
MRSingletonH(类名)
(在MRSingletonH后括号中填入类名, 生成方法instanceMRPerson
的方法声明)
@interface MRPerson : NSObject // 调用宏声明单例方法 MRSingletonH(Person) @end
- 3 在.h 文件中调用宏的方法
MRSingletonH(类名)
@interface MRPerson ()<NSCopying> @end @implementation MRPerson // 调用宏实现单例方法 MRSingletonM(MRPerson) @end
6、单例使用
#pragma mark --- 利用GCD实现单例 // 原始方法创建 MRPerson *person2 = [[MRPerson alloc] init]; // 单例方法创建 MRPerson *person1 = [MRPerson sharedPerson]; // copy MRPerson *person3 = [person2 copy]; NSLog(@"[MRPerson sharedPerson]---%@", person1); NSLog(@"[[MRPerson alloc] init]---%@", person2); NSLog(@"[person2 copy]---%@", person3); ViewController *viewController1 = [ViewController sharedViewController]; ViewController *viewController2 = [[ViewController alloc] init]; ViewController *viewController3 = [viewController2 copy]; NSLog(@"[ViewController sharedViewController]---%@", viewController1); NSLog(@"[[ViewController alloc] init]---%@", viewController2); NSLog(@"[viewController2 copy]---%@", viewController3);
2016-06-26 20:26:10.903 单例模式-OC[3818:214382] [MRPerson sharedPerson]---<MRPerson: 0x7bf2cdb0>2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [[MRPerson alloc] init]---<MRPerson: 0x7bf2cdb0>2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [person2 copy]---<MRPerson: 0x7bf2cdb0>2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [ViewController sharedViewController]---<ViewController: 0x7bf29c40>2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [[ViewController alloc] init]---<ViewController: 0x7bf29c40>2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [viewController2 copy]---<ViewController: 0x7bf29c40>
可以看出单例已经成功创建,每一个实例对象都指向同一块内存空间!!!(ps:这篇是OC版,后续会用swift实现)
- 创建"全世界最简单"の单例
- 简单创建单例
- 最简单单例模式
- 单例模式 最简单
- 最简单---单例模式
- 发布网站教程-全世界最简单的教程
- 最简单的java单例
- 最简单的单例模式
- IOS 最简单的单例模式
- 最简单的单例模式说明
- 最简单的单例模式
- 全世界你最美丽
- 最简单也最复杂的设计模式 单例
- 单例模式的简单创建 方法
- 单例模式的简单创建
- 可以说是全世界最简单的VB动态调用外部函数(附源代码)
- 机器学习原来如此有趣!全世界最简单的机器学习入门指南
- 机器学习原来如此有趣!全世界最简单的机器学习入门指南
- 08PL_SQL过程之执行select语句
- 09PL_SQL过程之执行insert语句
- 理解 Ubuntu 16.04 根目录下各个文件夹的功能(草稿)
- static静态变量的理解
- MYSQL-----索引
- 创建"全世界最简单"の单例
- Java NIO系列教程(五) 通道之间的数据传输
- php.ini 文件配置详解
- 10PL_SQL过程之执行if语句
- MongoDB安装
- HashMap快速了解
- Socket网络编程及其通信原理
- 下拉刷新上拉加载开源控件---MaterialRefreshLayout开源控件
- Node.js 初试啼声