一.什么是单例设计模式
1、简单说明:
(1)永远只分配一块内存来创建对象,实现allocWithZone方法
(2)提供一个类方法,返回内部唯一的一个变量
2、单例模式说明
(1)单例模式的作用 :可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问,从而方便地控制了实例个数,并节约系统资源。
(2)单例模式的使用场合:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),应该让这个类创建出来的对象永远只有一个。
(3)单例模式在ARC\MRC环境下的写法有所不同,需要编写2套不同的代码
可以用宏判断是否为ARC环境,后面的使用中会告诉你如何编写代码来适配两种不同的情况
二.在什么时候使用单例和使用单例的优缺点:
1.如果在项目中访问的是同一个对象,那么我们就应该提供一个全局的访问点给外界,此时使用单例可以减少对象的创建次数,节省内存的分配
2.创建单例对象可以高效的访问对象的方法,提高app的执行速率
3.定义单例对象更加符合苹果MVC的封装思想,体现出了高内聚,低耦合,代码更加简洁
缺点:
对象被创建以后,由于是单例对象(static修饰的对象),对象一旦创建就不会销毁,知道app完全意义上的退出才销毁对象
总结:
单例在项目中的是必不可少的,它可以使我们全局都可共享我们的数据。这只是简单的问题,大家根据自己的情况回答。
- 首先,单例写法有好几种,通常的写法是基于线程安全的写法,结合dispatch_once来使用,保证单例对象只会被创建一次。如果不小心销毁了单例,再调用单例生成方法是不会再创建的。
- 其次,由于单例是约定俗成的,因此在实际开发中通常不会去重写内存管理方法。
单例确实给我们带来的便利,但是它也会有代价的。单例一旦创建,整个App使用过程都不会释放,这会占用内存,因此不可滥用单例。
那么,同样作为工具类的使用,到底是使用单例还是类方法,这个就得看需求,如果说工具类不依赖任何属性的时候就是用类方法(类方法的使用在此就不展开说了)
三.如何实现单例
1.ARC下实现单例
[objc] view plain copy
- //定义一份变量(整个程序运行过程中,只有一份)
- +(instancetype)shareProductName{
- return [[self alloc]init];
- }
- //重写该方法,控制内存的分配,永远只分配一次存储空间
- +(instancetype)allocWithZone:(struct _NSZone *)zone{
- static id instance = nil;
- //里面的代码只会执行一次,
- //补充:如果把代码下载dispatch_once里面,那么它内部默认会进行加锁。
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- instance = [super allocWithZone:zone];
- });
- return instance;
- }
- -(instancetype)copyWithZone:(struct _NSZone *)zone{
- return self;
- }
2.MRC下实现单例
项目默认环境是ARC环境,将ARC环境转换为MRC的操作如下图:
非ARC中(MRC),单例模式的实现(比ARC多了几个步骤)
实现内存管理方法
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1; }
- (oneway void)release {}
- (id)autorelease { return self; }
[objc] view plain copy
- //定义一份变量(整个程序运行过程中,只有一份)
- +(instancetype)shareProductName{
- return [[self alloc]init];
- }
- //重写该方法,控制内存的分配,永远只分配一次存储空间
- +(instancetype)allocWithZone:(struct _NSZone *)zone{
- static id instance = nil;
- //里面的代码只会执行一次,
- //补充:如果把代码下载dispatch_once里面,那么它内部默认会进行加锁。
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- instance = [super allocWithZone:zone];
- });
- return instance;
- }
- -(oneway void)release{
- }
- -(instancetype)retain{
- return self;
- }
- -(instancetype)autorelease{
- return self;
- }
- -(NSUInteger)retainCount{
- return 1;
- }
3、把单例代码定义为一个带参数的宏
1>.新的困扰
弊端:如果又创建一个新的类,是否又要把文件代码拷贝一份,所以这里可以考虑把固定的代码写成宏。
由于项目中代码经常有移植的需要,要求项目中又有ARC的,又有非ARC的,应该怎么应用单例模式?
不管项目是ARC的还是非ARC的,这个宏都有用。可以先判断编译器的环境,判断当前环境是否是ARC的。
条件编译的使用:
2>.使用条件编译,并把单例模式的代码定义为宏。
新建一个.h头文件
把代码定义为宏,头文件中的代码如下:
[objc] view plain copy
- // ## : 连接字符串和参数
- #define CRJSingleton_h(name) + (instancetype)share##name;
- #if __has_feature(objc_arc)//arc环境
- #define CRJSingleton_m(name) + (instancetype)share##name{\
- return [[self alloc]init];\
- }\
- \
- +(instancetype)allocWithZone:(struct _NSZone *)zone{\
- static id instance = nil;\
- static dispatch_once_t onceToken;\
- dispatch_once(&onceToken,^{\
- instance = [super allocWithZone:zone];\
- });\
- return instance;\
- }\
- \
- -(id)copyWithZone:(struct _NSZone *)zone{\
- return self;\
- }
- #else
- #define CRJSingleton_m(name) + (instancetype)share##name{\
- return [[self alloc]init];\
- }\
- \
- +(instancetype)allocWithZone:(struct _NSZone *)zone{\
- static id instance = nil;\
- static dispatch_once_t onceToken;\
- dispatch_once(&onceToken,^{\
- instance = [super allocWithZone:zone];\
- });\
- return instance;\
- }\
- \
- -(id)copyWithZone:(struct _NSZone *)zone{\
- return self;\
- }\
- \
- -(oneway void)release{\
- \
- }\
- \
- -(instancetype)retain{\
- return self;\
- }\
- \
- -(instancetype)autorelease{\
- return self;\
- }\
- \
- -(NSUInteger)retainCount{\
- return 1;\
- }
- #endif
四.怎样用swift实现单例
swift创建单例的方式有好多种,下面我只写出最简洁的版本:
[objc] view plain copy
- //在swift中的单例
- class CRJSongleton: NSObject {
- // 常量保证只执行一次, let是线程安全的
- static let sharedInstance: CRJSongleton = CRJSongleton()
- }
为什么swift中这么简单的一句话就可以实现单例呢?
1.static 修饰的变量/常量在创建以后就一直存在,知道程序真正意义上的退出才销毁,从而达到了对象可以随时调用
2.let 修饰的是不可变的常量,本身就是线程安全的,常量可以保证只赋值一次以后不能再被修改,等价于GCD中的只执行一次dispatch_once
综上所述,用Swift实现单例就是这么滴简单,一句代码实现对象只允许被创建一次,且全局都可访问
原文:http://blog.csdn.net/github_34613936/article/details/51290356