iOS 单例(Singleton)总结 和第三库引用单例

引用:http://blog.csdn.net/lovefqing/article/details/8516536#t3

   http://blog.csdn.net/kindazrael/article/details/7917863

单例模式用于当一个类只能有一个实例的时候, 通常情况下这个“单例”代表的是某一个物理设备比如打印机,或是某种不可以有多个实例同时存在的虚拟资源或是系统属性比如一个程序的某个引擎或是数据。最简单的一个例子是,当用户打开QQ空间播放音乐的时候,这里就是一个单例,如果不是单例的话,点击其他页面QQ音乐就会自动从头开始播放。用单例模式加以控制是非常有必要的。

单例模式需要达到的目的

1. 封装一个共享的资源

2. 提供一个固定的实例创建方法

3. 提供一个标准的实例访问接口

单例模式的创建

本文以创建一个MySingletonClass的单例模式为例。首先,我们需要定义一个类MySingletonClass.

[cpp] view plaincopy

  1. @interface MySingletonClass:NSObject {
  2. }

并且为其添加一个类方法(注意,这里不是实例方法)+(id)sharedInstance;一个基本的实现写法如下:


static MySingletonClass *sharedInstance = nil;

  1. +(MySingletonClass *)sharedInstance{
  2. @synchronized(self) {
  3. if(sharedInstance == nil) {
  4. sharedInstance = [[MySingletonClass alloc]init];
  5. }
  6. }
  7. return sharedInstance;
  8. }

在上面的代码中(用到了关键字@synchronized是为了保证我们的单例的线程级别的安全,可以适用于多线程模式下。)static变量sharedCLDelegate用于存储一个单例的指针,并且强制所有对该变量的访问都必须通过类方法   +(id)sharedInstance,在对   +(id)sharedInstance第一次调用时候完成实例的创建。这里值得留意一下的是,上面代码中用的是[[selfclass] alloc],而不是 [MySingletonClass alloc],一般情况下这两种写法产生同样的效果.

对实例化的控制

为了完全的实现实例的单态性,必须通过一定手段来避免实例多次被创建。+(id)sharedInstance控制了单例的创建和访问,但是并不能控制其它地方的代码通过alloc方法来创建更多的实例,因此我们还要重载任何一个涉及到allocation的方法,这些方法包括   +new, +alloc,+allocWithZone:, -copyWithZone:, 以及 -mutableCopyWithZone:另外,+(id)sharedInstance也需要稍作修改。

  1. + (id)hiddenAlloc
  2. {
  3. return [super alloc];
  4. }
  5. + (id)alloc
  6. {
  7. NSLog(@"%@: use +sharedInstance instead of +alloc", [[self class] name]);
  8. return nil;
  9. }
  10. + (id)new
  11. {
  12. return [self alloc];
  13. }
  14. +(id)allocWithZone:(NSZone*)zone
  15. {
  16. return [self alloc];
  17. }
  18. -   (id)copyWithZone:(NSZone *)zone
  19. {   // -copy inherited from NSObject calls -copyWithZone:
  20. NSLog(@"MySingletonClass: attempt to -copy may be a bug.");
  21. [self retain];
  22. return self;
  23. }
  24. - (id)mutableCopyWithZone:(NSZone *)zone
  25. {
  26. // -mutableCopy inherited from NSObject calls -mutableCopyWithZone:
  27. return [self copyWithZone:zone];
  28. }
  29. +(id)sharedInstance修改如下:
  30. + (MySingletonClass *)sharedInstance {
  31. @synchronized(self) {
  32. if (sharedCLDelegate == nil)   {
  33. [[[self class] hiddenAlloc] init]; // assignment not done here
  34. }
  35. }
  36. return sharedCLDelegate;
  37. }

如果不考虑类的子类化,+hiddenAlloc这个方法可以省略。由于我们是用[selfclass]来实现类型的动态识别,用[[selfclass] hiddenAlloc]可以避免调用到被重载过的alloc方法。此外,hiddenAlloc也为可能的子类化提供了一个调用原始alloc方法的机会。上面重载过的alloc方法只是给出一个log信息并且返回nil。Copying方法里只是简单的增加了retain的计数并没有返回一个新的实例。这也正体现了单例模式的性质,因为技术上来讲,拷贝一个单例是错误的(因为是“单例”)所以在copyWithZone方法中我们给出了一个错误信息,当然也可以扔出一个exception。

单例的销毁

通常我们在   -(void)applicationWillTerminate:(UIApplication *)application方法中调用如下方法:

  1. + (void)attemptDealloc
  2. {
  3. if ([sharedCLDelegate retainCount] != 1)
  4. return;
  5. [sharedCLDelegate release];
  6. myInstance = nil;
  7. }

值得注意的是,上面这个attemptDealloc方法顾名思义,只是试图释放掉这个单例。如果retain的计数不为1,说明还有其他地方对该单例发送过retain消息。考虑到一个单例模式的生存周期是整个程序结束为止。所以,在程序的任何一个地方都没有必要向这个单例发送retain消息,即便是对这个单例有引用。而是调用sharedInstance方法来引用这个单例,这样做是安全的,也是合乎单例模式的技术含义的。

这里需要设置一个参数,手动管理内存。

iOS中的单例模式应用

iOS中好几个类都是采用了单例模式,比如NSApplication, NSFontManager,   NSDocumentController,NSHelpManager, NSNull,NSProcessInfo, NSScriptExecutionContext,   NSUserDefaults.

  1. 官方建议
  2. 由于自己设计单态模式存在一定风险,主要是考虑到可能在多线程情况下会出现的问题,因此苹果官方建议使用以下方式来实现单态模式:
  3. static MyGizmoClass *sharedGizmoManager = nil;
  4. + (MyGizmoClass*)sharedManager
  5. {
  6. @synchronized(self) {
  7. if (sharedGizmoManager == nil) {
  8. [[self alloc] init]; // assignment not done here
  9. }
  10. }
  11. return sharedGizmoManager;
  12. }
  13. + (id)allocWithZone:(NSZone *)zone
  14. {
  15. @synchronized(self) {
  16. if (sharedGizmoManager == nil) {
  17. sharedGizmoManager = [super allocWithZone:zone];
  18. return sharedGizmoManager;  // assignment and return on first allocation
  19. }
  20. }
  21. return nil; //on subsequent allocation attempts return nil
  22. }
  23. - (id)copyWithZone:(NSZone *)zone
  24. {
  25. return self;
  26. }
  27. - (id)retain
  28. {
  29. return self;
  30. }
  31. - (unsigned)retainCount
  32. {
  33. return UINT_MAX;  //denotes an object that cannot be released
  34. }
  35. - (void)release
  36. {
  37. //do nothing
  38. }
  39. - (id)autorelease
  40. {
  41. return self;
  42. }
  43. 由于单例模式基本要符合上面的设计,当有很多类都要设计成单例模式时,可以定义
  44. 一个单例模板的宏,以提高程序的重用和减少不必要错误。
  45. #define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
  46. \
  47. static classname *shared##classname = nil; \
  48. \
  49. + (classname *)shared##classname \
  50. { \
  51. @synchronized(self) \
  52. { \
  53. if (shared##classname == nil) \
  54. { \
  55. shared##classname = [[self alloc] init]; \
  56. } \
  57. } \
  58. \
  59. return shared##classname; \
  60. } \
  61. \
  62. + (id)allocWithZone:(NSZone *)zone \
  63. { \
  64. @synchronized(self) \
  65. { \
  66. if (shared##classname == nil) \
  67. { \
  68. shared##classname = [super allocWithZone:zone]; \
  69. return shared##classname; \
  70. } \
  71. } \
  72. \
  73. returnnil; \
  74. } \
  75. \
  76. - (id)copyWithZone:(NSZone *)zone \
  77. { \
  78. returnself; \
  79. } \
  80. \
  81. - (id)retain \
  82. { \
  83. returnself; \
  84. } \
  85. \
  86. - (NSUInteger)retainCount \
  87. { \
  88. return NSUIntegerMax; \
  89. } \
  90. \
  91. - (void)release \
  92. { \
  93. } \
  94. \
  95. - (id)autorelease \
  96. { \
  97. returnself; \
  98. }

用法:假设AppPreference类要实现单例

#import "AppPreference.h"

#import "SingletonTemplate.h"

@implementation AppPreference

//使用宏模版生成单例所需要的code

SYNTHESIZE_SINGLETON_FOR_CLASS(AppPreference)

//这是一个测试方法

+ (void)test {

//使用单例

AppPreference *appPreference = [AppPreference sharedAppPreference];

}

@end

时间: 2024-10-16 04:58:54

iOS 单例(Singleton)总结 和第三库引用单例的相关文章

【设计模式(三)】单例模式——单例有几种写法?

有一回对我说道,“你写过编程么?”我略略点一点头.他说,“写过,……我便考你一考.单例模式,是怎样写的?”我想,讨饭一样的人,也配考我么?便回过脸去,不再理会.孔乙己等了许久,很恳切的说道,“不能写罢?……我教给你,记着! 单例模式(Singleton Pattern) 单例模式是 Java 中最简单的设计模式之一.这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建.这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象. 单例模式三要素:1.单

Objective-C设计模式——单例Singleton(对象创建)

单例 和其它语言的单例产不多,可以说是最简单的一种设计模式了.但是有几个点需要注意下,单例就是一个类只有一个实例. 所以我们要想办法阻止该类产生别的实例,一般语言中都会将构造函数写为private.但是OC中的函数并没有限定符,所以我们需要用一些小技巧来屏蔽这一点. 应用场景 类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法. 这个唯一的实例只能通过类的子类化进行扩展,而且扩展的对象不会破坏客户端代码. 注意 1.OC中单例的实例变量要定义在.m文件 2.OC中单例需要

深入浅出单实例Singleton设计模式

单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面试中问得最多的一个设计模式了.这个设计模式主要目的是想在整个系统中只能出现一个类的实例.这样做当然是有必然的,比如你的软件的全局配置信息,或者是一个Factory,或是一个主控类,等等.你希望这个类在整个系统中只能出现一个实例.当然,作为一个技术负责人的你,你当然有权利通过使用非技术的手段来达到你的目的.比如:你在团队内部明文规定,“XX类只能有一个全局实例,如果某人使用两次以上,那么该人将被处于2000元的

(七)boost库之单例类

(七)boost库之单例类 一.boost.serialzation的单件实现 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源.如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案. 单例,通常在一个大型项目中单例是非常常见的,boost库没有提供专门的单例类,但可以在其它库中找到他的实现 #include <boost/serializat

第三项任务——用例建模

SRS文档——用例建模 一.spec概念 Specification, 又叫spec, 有两种: a) functional spec, 软件功能说明书, 主要用来说明软件的外部功能, 和用户的交互情况 (把软件当作一个黑盒子). b) technical spec, 软件技术说明书, 又叫 design doc, 设计文档, 主要用来说明软件内部的设计 (把软件当作一个透明的箱子). 二.用例建模 用例建模(Use Case Modeling)是使用用例的方法来描述系统的功能需求的过程,用例模

《iOS应用逆向工程》学习笔记(三)iOS文件权限

一个组可以包含多个用户,一个用户可以属于多个组. iOS中的每个文件都有一个属主用户和属主组.每个文件都具有一系列的权限. 在iOS中用3bit表示文件的使用权,从高位到低位分别是r(read), w(write), x(execute)权限. 文件和用户的关系存在三种可能性:(1)此用户是属主用户:(2)此用户不是属主用户,但在属主组里:(3)此用户既不是属主用户,也不在属主组里. 例如: 111101101代表rwxr-xr-x,其8进制为755,它表示该文件的属主用户拥有r, w, x权限

学习IOS开发UI篇--UI知识点总结(三) UIScrollView/UIPageControl/NSTimer

UIScrollView:常用属性 @property(nonatomic)   UIEdgeInsets     contentInset;               // default UIEdgeInsetsZero. add additional scroll area around content @property(nonatomic,getter=isPagingEnabled) BOOL   pagingEnabled;     // default NO. if YES,

Boottarp学习(三)表单

基础表单 表单主要功能是用来与用户做交流的一个网页控件,良好的表单设计能够让网页与用户更好的沟通.表单中常见的元素主要包括:文本输入框.下拉选择框.单选按钮.复选按钮.文本域和按钮等.其中每个控件所起的作用都各不相同,而且不同的浏览器对表单控件渲染的风格都各有不同. 同样,表单也是Bootstrap框架中的核心内容,下面向大家介绍Bootstrap框架中表单的制作. 表单源码查询 Bootstrap框架的表单,其源码占据了大量的代码,同样的,根据不同的Bootstrap版本,你可以轻松获取相应的

例6:设缓冲区DATA中有一组单字节有符号数,以0为结束标志。写一个程序实现如下功能:把前5个正数依次送入缓冲区PDATA,把前5个负数依次送入缓冲区MDATA;如正数或负数不足5个,则用0补足。

自解: 1 DSEG SEGMENT 2 DATA DB -1,1,-2,2,3,-3,-4,4,5,-5,-6,6,0 3 PDATA DB 0,0,0,0,0 4 MDATA DB 0,0,0,0,0 5 DSEG ENDS 6 ;------------------------------------ 7 CSEG SEGMENT 8 ASSUME DS:DSEG,CS:CSEG 9 START: 10 MOV AX,DSEG 11 MOV DS,AX 12 13 MOV BX,OFFSE