小编典典

在 Swift 中使用 dispatch_once 单例模型

all

我正在尝试制定一个适合在 Swift 中使用的单例模型。到目前为止,我已经能够获得一个非线程安全的模型:

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

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

        return Static.instance!
    }
}

将单例实例包装在静态结构中应该允许单个实例不与单例实例冲突而无需复杂的命名方案,并且应该使事情相当私密。显然,这个模型不是线程安全的。所以我试图添加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() })

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


阅读 147

收藏
2022-03-07

共1个答案

小编典典

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项目。

2022-03-07