最近接手一些项目,单例写法五花八门,初看一脸懵逼,总结一下
- 写法一 最推荐的写法,简洁 原理:利用静态成员自动满足dispatch_once规则
final class Single1 {
var name: String = "第一种单例" // 这是测试用的属性
static let shared = Single1()
private init() {}
}
当然,你要在初始化单例的时候有一些别的需要做,也可以稍微变形下
final class Single1 {
var name: String = "第一种单例" // 这是测试用的属性
static let shared = {
let instance = Single1()
// 其他代码
return instance
}()
private init() {}
}
- 注意:必须保证init方法的私有性,只有这样,才能保证单例是真正唯一的,避免外部对象通过访问init方法创建单例类的其他实例。
下面这段是我抄的
现在,你可能会有疑问:为何看不到dispatch_once?根据Apple Swift博客中的说法,以上方法都自动满足dispatch_once规则。这里有个帖子可以证明dispatch_once规则一直在起作用。全局变量(还有结构体和枚举体的静态成员)的Lazy初始化方法会在其被访问的时候调用一次。类似于调用’dispatch_once’以保证其初始化的原子性。这样就有了一种很酷的’单次调用’方式:只声明一个全局变量和私有的初始化方法即可。”–来自Apple’s Swift Blo(“The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic. This enables a cool way to use dispatch_once in your code: just declare a global variable with an initializer and mark it private.”)这就是Apple官方文档给我们的所有信息,但这些已经足够证明全局变量和结构体/枚举体的静态成员是支持”dispatch_once”特性的。现在,我们相信使用全局变量来“懒包装”单例的初始化方法到dispatch_once代码块中是100%安全的。
- 写法2 原理:利用全局变量自动满足dispatch_once规则
private let single2 = Single2()
final class Single2 {
var name: String = "第二种单例"
static var shared: Single2 {
single2
}
fileprivate init() {}
}
- 写法3 原理: 嵌套结构体变量 其实和第一种没什么区别,换个写法,也是利用 static 自动满足dispatch_once规则
final class Single3 {
var name: String = "第三种单例"
static var shared: Single3{
struct SingleStruct {
static let instance: Single3 = Single3()
}
return SingleStruct.instance
}
private init() {}
}
- 写法4 原理:同写法3,计算属性改成函数而已,而计算属性的本质就是函数
final class Single4 {
var name: String = "第四种单例"
static func shared() -> Single4 {
struct SingleStruct {
static var single = Single4()
}
return SingleStruct.single
}
}
- 写法5 原理:其实和前面没啥区别,OC入魔了,非要整个利用dispatch_once_t,纯粹脱了裤子放屁,最不推荐
// 由于Swift5没了利用dispatch_once_t,先利用静态成员的特性自己扩展一个
public extension DispatchQueue {
private static var onceToken: String = ""
// 保证被该函数嵌套的东西永远只执行一次 类似dispatch_once_t的效果
static func once(token: String, block:@escaping () -> Void) {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
if onceToken.contains(token){
return
}
onceToken.append(token)
block()
}
}
// 利用dispatch_once_t ,脱了裤子放屁,和之前没啥区别
class Single5 {
class var shared: Single5 {
struct SingleStruct {
static var instance: Single5? = nil
}
DispatchQueue.once(token: "single5") {
SingleStruct.instance = Single5()
}
return SingleStruct.instance!
}
}
- 常见错误写法 这里再说下,计算属性等同函数,以下两个写法没区别,就是自己在不断调用初始化函数,所以一定要注意
static var share: ImagePickerTool {
ImagePickerTool()
}
// 和上面写法等效,都是错误
class func `default`() -> ImagePickerTool { ImagePickerTool() }
今天的文章总结Swift5单例的几种写法和常见错误写法分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19805.html