巧用Singleton(单例)

来源:互联网 发布:sodu源码 编辑:程序博客网 时间:2024/04/29 20:41

一.什么是单例设计模式

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
  1. //定义一份变量(整个程序运行过程中,只有一份)  
  2. +(instancetype)shareProductName{  
  3.     return [[self alloc]init];  
  4. }  
  5. //重写该方法,控制内存的分配,永远只分配一次存储空间  
  6. +(instancetype)allocWithZone:(struct _NSZone *)zone{  
  7.     static id instance = nil;  
  8.     //里面的代码只会执行一次,  
  9.     //补充:如果把代码下载dispatch_once里面,那么它内部默认会进行加锁。  
  10.     static dispatch_once_t onceToken;  
  11.     dispatch_once(&onceToken, ^{  
  12.         instance = [super allocWithZone:zone];  
  13.     });  
  14.     return instance;  
  15. }  
  16. -(instancetype)copyWithZone:(struct _NSZone *)zone{  
  17.     return self;  
  18. }  

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
  1. //定义一份变量(整个程序运行过程中,只有一份)  
  2. +(instancetype)shareProductName{  
  3.     return [[self alloc]init];  
  4. }  
  5. //重写该方法,控制内存的分配,永远只分配一次存储空间  
  6. +(instancetype)allocWithZone:(struct _NSZone *)zone{  
  7.     static id instance = nil;  
  8.     //里面的代码只会执行一次,  
  9.     //补充:如果把代码下载dispatch_once里面,那么它内部默认会进行加锁。  
  10.     static dispatch_once_t onceToken;  
  11.     dispatch_once(&onceToken, ^{  
  12.         instance = [super allocWithZone:zone];  
  13.     });  
  14.     return instance;  
  15. }  
  16.   
  17. -(oneway void)release{  
  18.       
  19. }  
  20.   
  21. -(instancetype)retain{  
  22.     return self;  
  23. }  
  24. -(instancetype)autorelease{  
  25.     return self;  
  26. }  
  27. -(NSUInteger)retainCount{  
  28.     return 1;  
  29. }  

3、把单例代码定义为一个带参数的宏

1>.新的困扰

弊端:如果又创建一个新的类,是否又要把文件代码拷贝一份,所以这里可以考虑把固定的代码写成宏。

由于项目中代码经常有移植的需要,要求项目中又有ARC的,又有非ARC的,应该怎么应用单例模式?

不管项目是ARC的还是非ARC的,这个宏都有用。可以先判断编译器的环境,判断当前环境是否是ARC的。

条件编译的使用:


2>.使用条件编译,并把单例模式的代码定义为宏。

新建一个.h头文件


  

把代码定义为宏,头文件中的代码如下:

[objc] view plain copy
  1. // ## : 连接字符串和参数  
  2. #define CRJSingleton_h(name) + (instancetype)share##name;  
  3.   
  4. #if __has_feature(objc_arc)//arc环境  
  5. #define CRJSingleton_m(name) + (instancetype)share##name{\  
  6. return [[self alloc]init];\  
  7. }\  
  8. \  
  9. +(instancetype)allocWithZone:(struct _NSZone *)zone{\  
  10. static id instance = nil;\  
  11. static dispatch_once_t onceToken;\  
  12. dispatch_once(&onceToken,^{\  
  13. instance = [super allocWithZone:zone];\  
  14. });\  
  15. return instance;\  
  16. }\  
  17. \  
  18. -(id)copyWithZone:(struct _NSZone *)zone{\  
  19. return self;\  
  20. }  
  21.   
  22. #else  
  23. #define CRJSingleton_m(name) + (instancetype)share##name{\  
  24. return [[self alloc]init];\  
  25. }\  
  26. \  
  27. +(instancetype)allocWithZone:(struct _NSZone *)zone{\  
  28. static id instance = nil;\  
  29. static dispatch_once_t onceToken;\  
  30. dispatch_once(&onceToken,^{\  
  31. instance = [super allocWithZone:zone];\  
  32. });\  
  33. return instance;\  
  34. }\  
  35. \  
  36. -(id)copyWithZone:(struct _NSZone *)zone{\  
  37. return self;\  
  38. }\  
  39. \  
  40. -(oneway void)release{\  
  41. \  
  42. }\  
  43. \  
  44. -(instancetype)retain{\  
  45. return self;\  
  46. }\  
  47. \  
  48. -(instancetype)autorelease{\  
  49. return self;\  
  50. }\  
  51. \  
  52. -(NSUInteger)retainCount{\  
  53. return 1;\  
  54. }  
  55. #endif  


四.怎样用swift实现单例

swift创建单例的方式有好多种,下面我只写出最简洁的版本:

[objc] view plain copy
  1. //在swift中的单例  
  2.   
  3. class CRJSongleton: NSObject {  
  4.       
  5.     // 常量保证只执行一次, let是线程安全的  
  6.     static let sharedInstance: CRJSongleton = CRJSongleton()  
  7. }  

为什么swift中这么简单的一句话就可以实现单例呢?

1.static 修饰的变量/常量在创建以后就一直存在,知道程序真正意义上的退出才销毁,从而达到了对象可以随时调用

2.let 修饰的是不可变的常量,本身就是线程安全的,常量可以保证只赋值一次以后不能再被修改,等价于GCD中的只执行一次dispatch_once

综上所述,用Swift实现单例就是这么滴简单,一句代码实现对象只允许被创建一次,且全局都可访问


原文:http://blog.csdn.net/github_34613936/article/details/51290356

0 0
原创粉丝点击