iOS中单例模式的实现一般分为两种:MRC和ARC+GCD
1.MRC(非ARC)
非ARC的单例的实现方式:
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7 
      8 
      9 
      10 
      11 
      12 
      13 
      14 
      15 
      16 
      17 
      18 
      19 
      20 
      21 
      22 
      23 
      24 
      25 
      26 
      27 
      28 
      29 
      30 
      31 
      32  | 
    
      <span style="font-family: 仿宋; font-size: 15px;">#import <Foundation/Foundation.h>@interface 
NoARCSingleton:NSObject<span>//这个属性在后面调试有用处,而且也不要苦恼为什么是retain?不应该是copy么?请继续看下去,后面自然明白了<br></span>@property (nonatomic,retain) NSString *tempProperty;+(NoARCSingleton *)sharedInstance;@end@implementation 
NoARCSingleton static NoARCSingleton  *sharedInstance  = nil;//获取一个单例对象+ (BVNonARCSingleton *)sharedInstance {<br>//--------------------------------------------------<br>  if (sharedInstance == nil) {        sharedInstance = [[super 
allocWithZone:NULL] init];    }   return 
sharedInstance;<br>//--------------------------------------------------}//当第一次使用这个单例的时候,会调用这个init方法。-(id)init{   self 
= [super 
init];  if(self){   //通常在这里做一些相关的初始化任务  return 
self;    }      }//这个delloc方法永远都不会被调用,因为在程序的生命周期内,该单例都必须存在,该方法可以不用实现-(void)delloc{  [super 
dealloc];}//通过返回当前的单例对象的方式来防止实例化新的对象+ (id)allocWithZone:(NSZone*)zone {<br>  //线程相关的操作安全有</span>sharedInstance处理 | 
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7  | 
    
      <span style="font-family: 仿宋; font-size: 15px;">return 
[[self sharedInstance] retain]; } <br>//同样的,不希望生成单例的多个拷贝,必须重写 <br>- (id)copyWithZone:(NSZone *)zone { return self; } <br>//这个方法中什么操作都不需要该单例并不需要一个引用计数(retain counter)<br> -(id)retain { return self; }<br> //替换掉引用计数器,这样永远都不会release这个单例了<br> - (NSUInteger)retainCount { return NSUIntegerMax; } <br>// 该方法是空的——不希望用户release掉这个对象。<br> -(oneway void)release{ }<br> //除了返回单例外,什么也不做。<br> -(id)autorelease { return self; } <br>@end <br>//@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。 一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用。<br>//非ARC实现单例的方法是线程不安全的,如果有多个线程同时调用<span>sharedInstance方法获取一个实例,而<span>sharedInstance需要花费1-2s的时间,那么<span>NonARCSingleton的init方法可能会被多次的调用,也就是多个线程获得的单例有可能不是一个单例,解决这个线程不安全的方式是使用<a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html" target="_blank"><span class="edui-filter-underline">@synchronized</span></a><span>来创建互斥锁即可。<br>//<span>当然,该方法不能保证该单例中所有方法的调用都是线程安全的</span><br></span></span></span></span>//所以上面的横线之间的代码应该换成下面的代码@synchronized 
(self)</span>{     if(sharedInstance == nil)    {       sharedInstance = [[super 
allocWithZone:NULL] init];}<br>#param mark <span style="font-family: 仿宋; font-size: 15px;">-提醒:在iOS中,一般不建议使用非ARC来实现单例模式。更好的方法是使用ARC+GCD来实现。</span> | 
ARC实现的方式
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7  | 
    
      <span style="font-family: 仿宋; font-size: 15px;">#import "ARCSingleton.h"@interface 
ARCSingleton : NSObject<br>//调试之用和上面的代码作用类似的,这里为什么用weak呢?请继续看下去~<br><span>@property  ( nonatomic, weak) NSString  *tempProperty;</span>+ (ARCSingleton *)sharedInstance;@end@implementation 
ARCSingleton+ (ARCSingleton *) sharedInstance{<br><span style="line-height: 1.5;">      static  
ARCSingleton *sharedInstance = nil 
;</span></span> | 
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7 
      8 
      9 
      10 
      11 
      12 
      13 
      14 
      15 
      16 
      17 
      18  | 
    
      <span style="font-family: 仿宋; font-size: 15px;">     static  
dispatch_once_t onceToken = 0;  // 锁     dispatch_once (&onceToken, ^ {     // 最多调用一次       sharedInstance = [[self  
alloc] init];    });    return  
sharedInstance;}//当第一次使用这个单例时,会调用这个init方法-(id)init{    self 
= [super 
init];    if(self){       //初始化单例    }       return 
self;   }@end<br>//<span>在上面的代码中,调用</span><span class="edui-filter-underline"><a href="http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html" target="_blank">Grand Central Dispatch <br>(GCD)</a></span><span>中的</span><span class="edui-filter-underline"><a href="https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_once" target="_blank">dispatch_once</a></span><span>方法就可以确保ARCSingleton只被实例化一次。并且该方法是线程安全的,我们不用担心在不同的线程中,会获得不同的实例。(当然,该方法同样不能保证该单例中所有方法的调用都是线程安全的)。</span><br></span> | 
当然在ARC中,不用GCD也是可以做到线程安全的,跟之前非ARC代码中使用@synchronized一样,如下代码:
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7 
      8 
      9  | 
    
      <span style="font-family: 仿宋; font-size: 15px;"> // 不使用GCD,通过@synchronized@synchronized 
(self){    if(sharedInstance == nil)    {        sharedInstance = [[self 
alloc] init];    }}</span> | 
为了简化使用ARC+GCD来创建单例,可以使用下面这个宏
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7 
      8 
      9 
      10 
      11  | 
    
      #define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) \static dispatch_once_t onceToken = 0; \ static 
id sharedInstance = nil; \dispatch_once(&onceToken, ^{ \sharedInstance = block(); \}); \return 
sharedInstance; \<br><span style="font-family: 仿宋; font-size: 15px;">//如果对于macro有问题的话强烈建议去脑补下猫神的文章http://onevcat.com/2014/01/black-magic-in-macro/<br>//另外猫神的很多文章都是很深入的建议有时间多去细细品味</span> | 
宏写完了之后那就so easy了!
实例化方法实现:
| 
       1 
      2 
      3 
      4 
      5 
      6  | 
    
      + (BVARCSingleton *) sharedInstance{    DEFINE_SHARED_INSTANCE_USING_BLOCK(^{       return 
[[self alloc] init];    });}<br>//Done | 
单例的使用:单例的使用方法很简单,在代码中的任意位置,如下使用即可:
  
  在BVAppDelegate.m中添加头文件:
  #import 
"NonARCSingleton.h"
  #import "ARCSingleton.h"
| 
       1 
      2 
      3 
      4 
      5 
      6 
      7 
      8 
      9 
      10 
      11 
      12 
      13 
      14 
      15  | 
    
      - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary 
*)launchOptions{      [NonARCSingleton sharedInstance].tempProperty = @"非ARC单例的实现";       NSLog(@"%@", [BVNonARCSingleton sharedInstance].tempProperty);       [ARCSingleton sharedInstance].tempProperty = @"ARC单例的实现";       NSLog(@"%@", [ARCSingleton sharedInstance].tempProperty);        return 
YES;} | 
附加干货
__weak,__strong
  很少会见到 __weak 和 __strong 
出现在声明中,但我们需要对它们有一定的了解。 
默认情况下,一个指针都会使用 
__strong 
属性,表明这是一个强引用。这意味着,只要引用存在,对象就不能被销毁。这是一种所期望的行为:当所有(强)引用都去除时,对象才能被收集和释放。不过, 
有时我们却希望禁用这种行为:一些集合类不应该增加其元素的引用,因为这会引起对象无法释放。在这种情况下,我们需要使用弱引用(不用担心,内置的集合类 
就是这么干的),使用 __weak 关键字。NSHashTable 就是一个例子。当被引用的对象消失时,弱引用会自动设置为 nil。Cocoa 的 
nsnotificationcenter 就是这么一个例子,虽然这已经超出纯 Objective-C 的语言范畴 .
iOS中单例模式:MRC和ARC+GCD实现,布布扣,bubuko.com
原文地址:http://www.cnblogs.com/azxfire/p/3778851.html