一个单例的实现

GCD还提供单次初始化支持,这个与pthread中的函数 pthread_once 很相似。GCD提供的方式的优点在于它使用block而非函数指针,这就允许更自然的代码方式。
  这个特性的主要用途是惰性单例初始化或者其他的线程安全数据共享。典型的单例初始化技术看起来像这样(线程安全的):

帮助
01
02
03
04
05
06
07
08
09
10
+ (id)sharedWhatever
{
     static Whatever *whatever = nil;
     @synchronized([Whatever class ])
     {
         if (!whatever)
             whatever = [[Whatever alloc] init];
     }
     return whatever;
}

  这挺好的,但是代价比较昂贵;每次调用 +sharedWhatever 函数都会付出取锁的代价,即使这个锁只需要进行一次。确实有更风骚的方式来实现这个,使用类似双向锁或者是原子操作的东西,但是这样挺难弄而且容易出错。创建单例有更加简单的方式,使用GCD,我们可以这样重写上面的方法,使用函数 dispatch_once:

帮助
1
2
3
4
5
6
7
8
9
+ (id)sharedWhatever
{
     static dispatch_once_t pred;
     static Whatever *whatever = nil;
     dispatch_once(&pred, ^{
         whatever = [[Whatever alloc] init];
     });
     return whatever;
}

  该方法有很多优势:
  1  线程安全
  2  很好满足静态分析器要求
  3  和自动引用计数(ARC)兼容
  4  仅需要少量代码
  这个稍微比 @synchronized方法简单些,并且GCD确保以更快的方式完成这些检测,它保证block中的代码在任何线程通过 dispatch_once 调用之前被执行,但它不会强制每次调用这个函数都让代码进行同步控制。实际上,如果你去看这个函数所在的头文件,你会发现目前它的实现其实是一个宏,进行了内联的初始化测试,这意味着通常情况下,你不用付出函数调用的负载代价,并且会有更少的同步控制负载。





在开发中我们会用到NSNotificationCenter、NSFileManager等,获取他们的实例通过[NSNotificationCenter defaultCenter]和[NSFileManager defaultManager]来获取,其实这就是单例。

我们先看下函数void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);其中第一个参数predicate,该参数是检查后面第二个参数所代表的代码块是否被调用的谓词,第二个参数则是在整个应用程序中只会被调用一次的代码块。dispach_once函数中的代码块只会被执行一次,而且还是线程安全的。
       接下来我们来实现自己的单例,这里有一个SchoolManager类,为这个类实现单例
[cpp]  
+(SchoolManager *)sharedInstance  
{  
    static SchoolManager *sharedManager;  
      
    static dispatch_once_t onceToken;  
    dispatch_once(&onceToken, ^{  
        sharedManager = [[SchoolManager alloc] init];  
    });  
      
    return sharedManager;  
}  
到目前为止,我们就实现了一个单例,一切就搞定了,是不是很简单!
使用就按照如下方式获取唯一实例即可:
[cpp]  
SchoolManager *schoolManager = [SchoolManager sharedInstance];  
 
以上就简单介绍了使用dispatch_once函数实现单例的方法,欢迎大家补充并讨论!

你可能感兴趣的:(类,线程安全,实例,应用程序,cpp)