应用dispatch_once创建单例以及其他2中方式

无论是爱还是恨,你都需要单例。实际上每个iOS或Mac OS应用都至少会有 UIApplicationNSApplication.
什么是单例呢?Wikipedia是如此定义的:
在软件工程中,单例是一种用于实现单例的数学概念,即将类的实例化限制成仅一个对象的设计模式。
或者我的理解是:
单例是一种类,该类只能实例化一个对象。
    尽管这是单例的实际定义,但在Foundation框架中不一定是这样。比如 NSFileMangerNSNotificationCenter,分别通过它们的类方法 defaultManagerdefaultCenter获取。尽管不是严格意义的单例,这些类方法返回一个可以在应用的所有代码中访问到的类的共享实例。在本文中我们也会采用该方法。
    使用Objective-C实现单例模式的最佳方式向来有很多争论,开发者(包括Apple在内)似乎每几年就会改变他们的想法。当Apple引入了 Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0),他们也引入了一个很适合用于实现单例模式的函数。
    该函数就是 dispatch_once
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
    该函数接收一个 dispatch_once用于检查该代码块是否已经被调度的谓词(是一个长整型,实际上作为 BOOL使用)。它还接收一个希望在应用的生命周期内仅被调度一次的代码块,对于本例就用于shared实例的实例化。
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如 @synchronized之类的来防止使用多个线程或者队列时不同步的问题。
    Apple的 GCD Documentation证实了这一点:
如果被多个线程调用,该函数会同步等等直至代码块完成。
    实际要如何使用这些呢?
    好吧,假设有一个 AccountManager类,你想在整个应用中访问该类的共享实例。你可以按如下代码简单实现一个类方法:
+ (AccountManager *)sharedManager { 
    static AccountManager *sharedAccountManagerInstance = nil; 

    static dispatch_once_t predicate; dispatch_once(&predicate, ^{       
          sharedAccountManagerInstance = [[self alloc] init]; 
    });

    return sharedAccountManagerInstance; 

}
    这就意味着你任何时候访问共享实例,需要做的仅是:
AccountManager *accountManager = [AccountManager sharedManager];
    就这些,你现在在应用中就有一个共享的实例,该实例只会被创建一次。
    该方法有很多优势: 
           1 线程安全
           2 很好满足静态分析器要求
           3 和自动引用计数(ARC)兼容 
           4 仅需要少量代码
        该方法的劣势就是它允许创建一个非共享的实例(其实无妨):
    AccountManager *accountManager = [[AccountManager alloc] init];
        有些时候你希望有这种行为,但如果正在想要的是仅一个实例被实例化就需要注意这点。
    宏定义:

    为了简化使用ARC+GCD来创建单例,可以定义下面这样的一个宏:
    1.#define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) \
    2.static dispatch_once_t onceToken = 0; \
    3.__strong static id sharedInstance = nil; \
    4.dispatch_once(&onceToken, ^{ \
    5.sharedInstance = block(); \
    6.}); \
    7.return sharedInstance; \


    实例化的实现方法如下所示:
    1.+ (BVARCSingleton *) sharedInstance
    2.{
    3.    DEFINE_SHARED_INSTANCE_USING_BLOCK(^{
    4.        return [[self alloc] init];
    5.    });
    6.}


    -------------------------------------附-----------------------------------
    利用一下两种方式同样可以实现该功能:
    1, 在AppDelegate中声明并初始化全局变量, 然后在需要使用该变量的地方插入如下的代码:
    //取得AppDelegate,在iOS中,AppDelegat被设计成了单例模式
    xxxAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    appDelegate.Your Variable;即可。
    2,(未验证)
    使用 extern 关键字

    在AppDelegate.m或AppDelegate.h中写入你需要的全局变量名,例如:

    //数据库实例
    FMDatabase *db ;  

    注意:在定义全局变量的时候不能初始化,否则会报错!

      在需要调用的.M文件中声明  

    extern FMDatabase *db ; 

     使用全局变量:和使用普通变量一样使用。




    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值