我正在努力制定一个合适的单例模型用于Swift的使用。到目前为止,我已经能够得到一个非线程安全的模型工作为:

class var sharedInstance: TPScopeManager {
    get {
        struct Static {
            static var instance: TPScopeManager? = nil
        }

        if !Static.instance {
            Static.instance = TPScopeManager()
        }

        return Static.instance!
    }
}

将单例实例包装在Static结构中应该允许单个实例不与单例实例发生冲突,而不需要复杂的命名方案,并且它应该使事情相当私密。但是,这个模型显然不是线程安全的。所以我尝试将dispatch_once添加到整个事情中:

class var sharedInstance: TPScopeManager {
    get {
        struct Static {
            static var instance: TPScopeManager? = nil
            static var token: dispatch_once_t = 0
        }

        dispatch_once(Static.token) { Static.instance = TPScopeManager() }

        return Static.instance!
    }
}

但是我在dispatch_once行上得到了一个编译器错误:

不能将表达式的类型“Void”转换为类型“()”

我尝试了几种不同的语法变体,但它们似乎都有相同的结果:

dispatch_once(Static.token, { Static.instance = TPScopeManager() })

在Swift中dispatch_once的正确用法是什么?我最初认为问题出在错误消息中的()块上,但我看得越多,就越觉得可能是正确定义dispatch_once_t的问题。


当前回答

我的实现方式在Swift…

ConfigurationManager.swift

import Foundation

    let ConfigurationManagerSharedInstance = ConfigurationManager()
 class ConfigurationManager : NSObject {
    var globalDic: NSMutableDictionary = NSMutableDictionary()

class var sharedInstance:ConfigurationManager {
    return ConfigurationManagerSharedInstance

}

init() {

    super.init()

    println ("Config Init been Initiated, this will be called only onece irrespective of many calls")   

}

从应用程序的任何屏幕访问globalDic。

读:

 println(ConfigurationManager.sharedInstance.globalDic)  

写:

 ConfigurationManager.sharedInstance.globalDic = tmpDic // tmpDict is any value that to be shared among the application

其他回答

tl;dr:如果你使用的是Swift 1.2或更高版本,使用类常量方法;如果你需要支持更早的版本,使用嵌套结构方法。

根据我使用Swift的经验,有三种方法来实现支持延迟初始化和线程安全的单例模式。

类常量

class Singleton  {
   static let sharedInstance = Singleton()
}

这种方法支持延迟初始化,因为Swift会延迟初始化类常量(和变量),并且通过let的定义是线程安全的。这是现在官方推荐的实例化单例的方法。

在Swift 1.2中引入了类常量。如果您需要支持早期版本的Swift,请使用下面的嵌套结构方法或全局常量。

嵌套的结构体

class Singleton {
    class var sharedInstance: Singleton {
        struct Static {
            static let instance: Singleton = Singleton()
        }
        return Static.instance
    }
}

这里我们使用嵌套结构的静态常量作为类常量。这是针对Swift 1.1及更早版本中缺少静态类常量的一种变通方法,并且仍然可以作为函数中缺少静态常量和变量的一种变通方法。

dispatch_once

将传统的Objective-C方法移植到Swift。我很确定这种方法与嵌套结构方法相比没有优势,但我还是把它放在这里,因为我发现语法上的差异很有趣。

class Singleton {
    class var sharedInstance: Singleton {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: Singleton? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = Singleton()
        }
        return Static.instance!
    }
}

有关单元测试,请参阅此GitHub项目。

有更好的办法。你可以像这样在你的类声明上面声明一个全局变量:

var tpScopeManagerSharedInstance = TPScopeManager()

这只是调用你的默认init或任何init和全局变量是dispatch_once在Swift默认。然后在任何你想要引用的类中,你只需要这样做:

var refrence = tpScopeManagerSharedInstance
// or you can just access properties and call methods directly
tpScopeManagerSharedInstance.someMethod()

所以基本上你可以去掉整个共享实例代码块。

我的实现方式在Swift…

ConfigurationManager.swift

import Foundation

    let ConfigurationManagerSharedInstance = ConfigurationManager()
 class ConfigurationManager : NSObject {
    var globalDic: NSMutableDictionary = NSMutableDictionary()

class var sharedInstance:ConfigurationManager {
    return ConfigurationManagerSharedInstance

}

init() {

    super.init()

    println ("Config Init been Initiated, this will be called only onece irrespective of many calls")   

}

从应用程序的任何屏幕访问globalDic。

读:

 println(ConfigurationManager.sharedInstance.globalDic)  

写:

 ConfigurationManager.sharedInstance.globalDic = tmpDic // tmpDict is any value that to be shared among the application
final class MySingleton {
     private init() {}
     static let shared = MySingleton()
}

那就叫它;

let shared = MySingleton.shared

我更喜欢这样的实现:

class APIClient {

}

var sharedAPIClient: APIClient = {
    return APIClient()
}()

extension APIClient {
    class func sharedClient() -> APIClient {
        return sharedAPIClient
    }
}