zoukankan      html  css  js  c++  java
  • 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.       
    3. }  

    并且为其添加一个类方法(注意,这里不是实例方法)+(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.   
    6.   
    7. + (id)alloc  
    8. {  
    9.     NSLog(@"%@: use +sharedInstance instead of +alloc", [[self class] name]);  
    10.     return nil;  
    11. }  
    12.   
    13.   
    14. + (id)new  
    15. {  
    16.     return [self alloc];  
    17. }  
    18.   
    19. +(id)allocWithZone:(NSZone*)zone  
    20. {  
    21.     return [self alloc];  
    22. }  
    23.   
    24. -   (id)copyWithZone:(NSZone *)zone  
    25. {   // -copy inherited from NSObject calls -copyWithZone:  
    26.     NSLog(@"MySingletonClass: attempt to -copy may be a bug.");  
    27.     [self retain];  
    28.     return self;  
    29. }  
    30.   
    31. - (id)mutableCopyWithZone:(NSZone *)zone  
    32. {  
    33.     // -mutableCopy inherited from NSObject calls -mutableCopyWithZone:  
    34.     return [self copyWithZone:zone];  
    35. }  
    36.   
    37. +(id)sharedInstance修改如下:  
    38.   
    39. + (MySingletonClass *)sharedInstance {  
    40.     @synchronized(self) {  
    41.         if (sharedCLDelegate == nil)   {  
    42.             [[[self class] hiddenAlloc] init]; // assignment not done here  
    43.         }  
    44.     }  
    45.     return sharedCLDelegate;  
    46. }  

    如果不考虑类的子类化,+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.   
    6.     [sharedCLDelegate release];  
    7.     myInstance = nil;  
    8. }  

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

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

    iOS中的单例模式应用

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

     

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

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

    #import "AppPreference.h"

    #import "SingletonTemplate.h"

    @implementation AppPreference

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

    SYNTHESIZE_SINGLETON_FOR_CLASS(AppPreference)

    //这是一个测试方法

    + (void)test {

        //使用单例

        AppPreference *appPreference = [AppPreference sharedAppPreference];

    }

    @end

  • 相关阅读:
    HUST第八届程序设计竞赛-G小乐乐打游戏(双bfs)
    HDU-1575-Tr A(矩阵快速幂模板)
    HDU-1061-Rightmost Digit (快速幂模板)
    HihoCoder 1142-三分求极值(三分模板)
    Aizu ITP2_6_A(二分模板)
    Codeforces-938D-Buy a Ticket(最短路设虚拟节点+Dijk优先队列优化)
    POJ-1797-Heavy Transportation(最短路变形)
    HDU-5137-How Many Maos Does the Guanxi Worth(最短路删点)
    POJ-1094-Sorting It All Out (拓扑排序)(判断环和排名是否唯一)
    HDU-1869-六度分离(多源到多源最短路)
  • 原文地址:https://www.cnblogs.com/i0ject/p/4120639.html
Copyright © 2011-2022 走看看