总结Swift5单例的几种写法和常见错误写法

总结Swift5单例的几种写法和常见错误写法注意:必须保证init方法的私有性,只有这样,才能保证单例是真正唯一的,避免外部对象通过访问init方法创建单例类的其他实例。

最近接手一些项目,单例写法五花八门,初看一脸懵逼,总结一下

  • 写法一 最推荐的写法,简洁 原理:利用静态成员自动满足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

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注