Dav*_*rry 563 singleton dispatch swift
我正在尝试找出适合在Swift中使用的单例模型.到目前为止,我已经能够得到一个非线程安全模型:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
}
if !Static.instance {
Static.instance = TPScopeManager()
}
return Static.instance!
}
}
Run Code Online (Sandbox Code Playgroud)
在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!
}
}
Run Code Online (Sandbox Code Playgroud)
但我得到一个编译器错误dispatch_once:
无法将表达式的类型'Void'转换为'()'类型
我已经尝试了几种不同的语法变体,但它们似乎都有相同的结果:
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
Run Code Online (Sandbox Code Playgroud)
dispatch_once使用Swift 的正确用法是什么?我最初认为问题出在块中,因为dispatch_once错误消息,但我看的越多,我认为可能是获得()正确定义的问题.
hpi*_*que 705
tl; dr:如果使用Swift 1.2或更高版本,则使用类常量方法,如果需要支持早期版本,则使用嵌套结构方法.
根据我使用Swift的经验,有三种方法可以实现支持延迟初始化和线程安全的Singleton模式.
class Singleton {
static let sharedInstance = Singleton()
}
Run Code Online (Sandbox Code Playgroud)
这种方法支持延迟初始化,因为Swift懒惰地初始化类常量(和变量),并且通过定义是线程安全的let.这是现在官方推荐的实例化单例的方法.
类常量是在Swift 1.2中引入的.如果需要支持早期版本的Swift,请使用下面的嵌套结构方法或全局常量.
class Singleton {
class var sharedInstance: Singleton {
struct Static {
static let instance: Singleton = Singleton()
}
return Static.instance
}
}
Run Code Online (Sandbox Code Playgroud)
这里我们使用嵌套结构的静态常量作为类常量.这是Swift 1.1及更早版本中缺少静态类常量的一种解决方法,并且仍然可以作为函数中缺少静态常量和变量的解决方法.
传统的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!
}
}
Run Code Online (Sandbox Code Playgroud)
请参阅此GitHub项目以进行单元测试.
Dav*_*rry 173
由于Apple现在澄清了静态结构变量的初始化既懒又包裹在dispatch_once中(参见帖子末尾的注释),我认为我的最终解决方案将是:
class WithSingleton {
class var sharedInstance: WithSingleton {
struct Singleton {
static let instance = WithSingleton()
}
return Singleton.instance
}
}
Run Code Online (Sandbox Code Playgroud)
这利用了静态结构元素的自动延迟,线程安全初始化,安全地隐藏了消费者的实际实现,保持所有紧凑区分以便易读,并消除了可见的全局变量.
Apple已澄清懒惰初始化程序是线程安全的,因此不需要dispatch_once或类似的保护
全局变量(也适用于结构和枚举的静态成员)的惰性初始化程序在第一次访问全局时运行,并作为dispatch_once启动,以确保初始化是原子的.这样就可以在代码中使用dispatch_once:只需使用初始化程序声明一个全局变量并将其标记为私有.
从这里开始
Jac*_*ack 163
对于Swift 1.2及更高版本:
class Singleton {
static let sharedInstance = Singleton()
}
Run Code Online (Sandbox Code Playgroud)
有了正确性证明(所有信用都在这里),现在几乎没有理由使用任何以前的单身人士方法.
更新:现在这是官方文档中描述的定义单身人士的官方方式!
至于使用staticvs的担忧class.static即使class变量可用,也应该使用它.单例并不意味着被子类化,因为这将导致基本单例的多个实例.使用static以美丽,Swifty的方式强制执行此操作.
对于Swift 1.0和1.1:
随着最近Swift的变化,主要是新的访问控制方法,我现在倾向于使用全局变量来实现单例的更清晰的方式.
private let _singletonInstance = SingletonClass()
class SingletonClass {
class var sharedInstance: SingletonClass {
return _singletonInstance
}
}
Run Code Online (Sandbox Code Playgroud)
随着斯威夫特博客文章中提到在这里:
全局变量(也适用于结构和枚举的静态成员)的惰性初始化程序在第一次访问全局时运行,并作为dispatch_once启动,以确保初始化是原子的.这样就可以在代码中使用dispatch_once:只需使用初始化程序声明一个全局变量并将其标记为私有.
这种创建单例的方法是线程安全,快速,懒惰,并且还可以免费桥接到ObjC.
Flo*_*ian 46
Swift 1.2或更高版本现在支持类中的静态变量/常量.所以你可以使用一个静态常量:
class MySingleton {
static let sharedMySingleton = MySingleton()
private init() {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
Kri*_*lci 34
有一种更好的方法.你可以在类的decleration之上声明一个全局变量,就像这样
var tpScopeManagerSharedInstance = TPScopeManager()
Run Code Online (Sandbox Code Playgroud)
这只是在Swift中调用默认初始化或默认的init和全局变量dispatch_once.然后在您想要获得参考的任何课程中,您只需执行以下操作:
var refrence = tpScopeManagerSharedInstance
// or you can just access properties and call methods directly
tpScopeManagerSharedInstance.someMethod()
Run Code Online (Sandbox Code Playgroud)
所以基本上你可以摆脱整个共享实例代码块.
Rya*_*yan 27
Swift单例在Cocoa框架中作为类函数公开,例如NSFileManager.defaultManager(),NSNotificationCenter.defaultCenter()所以我觉得作为镜像这种行为的类函数更有意义,而不是像其他一些解决方案那样使用的类变量,例如
class MyClass {
private static let _sharedInstance = MyClass()
class func sharedInstance() -> MyClass {
return _sharedInstance
}
}
Run Code Online (Sandbox Code Playgroud)
检索单身人士MyClass.sharedInstance().
Adr*_*eil 16
根据Apple文档,它已多次重复,在Swift中执行此操作的最简单方法是使用静态类型属性:
class Singleton {
static let sharedInstance = Singleton()
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您正在寻找一种方法来执行除简单构造函数调用之外的其他设置,则秘诀是使用立即调用的闭包:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
Run Code Online (Sandbox Code Playgroud)
这保证是线程安全的,只能初始化一次.
Ada*_*aka 16
Swift 4+
protocol Singleton: class {
static var sharedInstance: Self { get }
}
final class Kraken: Singleton {
static let sharedInstance = Kraken()
private init() {}
}
Run Code Online (Sandbox Code Playgroud)
小智 8
看看Apple的示例代码,我遇到了这种模式.我不确定Swift如何处理静态,但这在C#中是线程安全的.我包括Objective-C互操作的属性和方法.
struct StaticRank {
static let shared = RankMapping()
}
class func sharedInstance() -> RankMapping {
return StaticRank.shared
}
class var shared:RankMapping {
return StaticRank.shared
}
Run Code Online (Sandbox Code Playgroud)
简单来说,
class Manager {
static let sharedInstance = Manager()
private init() {}
}
Run Code Online (Sandbox Code Playgroud)
您可能需要阅读文件和初始化
全局变量的延迟初始化程序(也适用于结构和枚举的静态成员)在第一次访问全局时运行,并且启动
dispatch_once以确保初始化是原子的.
| 归档时间: |
|
| 查看次数: |
125995 次 |
| 最近记录: |