2012-09-22 136 views
4

我已经看到了这个特定的实施Singleton模式随处可见:Singleton模式实现

+ (CargoBay *)sharedManager { 
    static CargoBay *_sharedManager = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     _sharedManager = [[CargoBay alloc] init]; 
    }); 
    return _sharedManager; 
} 

,它似乎被接纳为好的做法(这其中尤其是从CargoBay)。

我不明白的唯一部分是第一行static CargoBay *_sharedManager = nil;

为什么你将static变量设置为nil

回答

8

这只是一个可读性,惯例和实践的问题。这不是真的需要,因为:

一。它的价值永远不会被检查。在老单的实现有曾经是著名的

+ (id)sharedInstance 
{ 
    static SomeClass *shared = nil; 
    if (shared == nil) 
     shared = [[SomeClass alloc] init]; 

    return shared; 
} 

码 - 此方法的工作,支持变量被初始化到零,因为如果不是零的第一次,它会错误地省略if部分中的alloc-init并返回一个垃圾指针。但是,使用GCD解决方案时,不再需要无检查 - GCD处理'只执行一次'编译指示。

二。但是:静态变量隐含地初始化为零。所以即使你只写static id shared;它最初也会是nil

三。为什么这可能是好的做法?因为,尽管我提到了前两个原因,但让源代码的读者知道某些内容已明确初始化为零仍然更具可读性。或者甚至可能存在一些不合格的实现,其中静态变量未正确自动初始化,然后应采取此操作。

+0

很好,谢谢你的回答。但是,为什么静态? – Francesco

+0

@Francesco你是什么意思? – 2012-09-22 15:43:46

+0

通过声明共享实例'static',我们将其生命周期延长到整个应用程序的生命周期,对吧? Singleton模式的要点是有一个共享实例,可以在我们的应用程序的任何地方使用,但是为什么我们每次调用该方法时都会创建一个新实例? – Francesco

1

您将它设置为零以确保您获得干净的实例。

这是你想要做什么更可读的版本:

+ (GlobalVariables *)sharedInstance { 
    // the instance of this class is stored here 
    static GlobalVariables *myInstance = nil; 

    // check to see if an instance already exists 
    if (nil == myInstance) { 
     myInstance = [[[self class] alloc] init]; 
    } 
    // return the instance of this class 
    return myInstance; 
} 

但也有职位的负载各地展示这可怎么可能不是线程安全的,所以移动到你的方法的混合体上面和我发布的东西,你得到这个:

// Declared outside Singleton Manager  
static SingletonClass *myInstance = nil; 
+ (GlobalVariables *)sharedInstance { 
    if (nil != myInstance) { 
     return myInstance; 
    } 

    static dispatch_once_t pred;  // Lock 
    dispatch_once(&pred, ^{    // This code is called at most once per app 
     myInstance = [[GlobalVariables alloc] init]; 
    }); 

    return myInstance; 
} 
+0

“你引用的代码块不会总是重复使用同一个实例” - 这只是*不正确。* – 2012-09-22 15:10:24

+0

由GCD覆盖执行一次的代码是dispatch_once块内的代码,而不是其外部的代码。我写的内容主要是试图通过简单地添加对共享实例的检查来提高可读性。在Singleton访问器之外移动共享实例的分配使得整个过程变得清晰。 – MystikSpiral

+0

'赋值'不是一个真正的'赋值',而是一个初始化。因为被初始化的变量是'static',所以它将被执行(初始化)一次,不管它的范围,它被声明/初始化的地方等***维基百科的[第一个例子](http: //en.wikipedia.org/wiki/Static_variable)明确指出*“x仅在func()的三次调用中初始化一次...”...... * – 2012-09-22 15:23:22