我正在努力制定一个合适的单例模型用于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的问题。


当前回答

斯威夫特5.2

您可以用Self指向类型。所以:

static let shared = Self()

并且应该在一个类型中,比如:

class SomeTypeWithASingletonInstance {
   static let shared = Self()
}

其他回答

Swift单例在Cocoa框架中作为类函数公开,例如NSFileManager.defaultManager(), NSNotificationCenter.defaultCenter()。因此,作为一个类函数来反映这种行为比作为其他解决方案的类变量更有意义。例句:

class MyClass {

    private static let _sharedInstance = MyClass()

    class func sharedInstance() -> MyClass {
        return _sharedInstance
    }
}

通过MyClass.sharedInstance()检索单例。

唯一正确的方法如下。

final class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()
        // setup code if anything
        return instance
    }()

    private init() {}
}

访问

let signleton = Singleton.sharedInstance

原因:

静态类型属性保证只被惰性初始化一次,即使在多线程同时访问时也是如此,因此不需要使用dispatch_once 私有化init方法,使实例不能由其他类创建。 因为你不希望其他类继承Singleton类。

我使用以下语法:

public final class Singleton {    
    private class func sharedInstance() -> Singleton {
        struct Static {
            //Singleton instance.
            static let sharedInstance = Singleton()
        }
        return Static.sharedInstance
    }

    private init() { }

    class var instance: Singleton {
        return sharedInstance()
    }
}

从Swift 1.2到Swift 4都可以使用,有几个优点:

提醒用户不要子类化实现 防止创建额外的实例 确保惰性创建和唯一实例化 通过允许以Singleton.instance的形式访问instance来缩短语法(avoid ())

斯威夫特 4+

protocol Singleton: class {
    static var sharedInstance: Self { get }
}

final class Kraken: Singleton {
    static let sharedInstance = Kraken()
    private init() {}
}

在看到David的实现之后,似乎没有必要使用单个类函数instanceMethod,因为let所做的事情与sharedInstance类方法几乎相同。你所要做的就是把它声明为一个全局常数,就是这样。

let gScopeManagerSharedInstance = ScopeManager()

class ScopeManager {
   // No need for a class method to return the shared instance. Use the gScopeManagerSharedInstance directly. 
}