iOS-Swift

Swift单例的正确写法

2017-06-21  本文已影响250人  plantseeds

虽然入坑时曾经用Swift2.0写过4个多月代码,后来换公司项目又用OC了,现在打算用Swift写代码了. OC->Swift->OC->Swift😂

本想创建一个Struct单例

struct BannerQueue {
    static let `default` = BannerQueue()
    var banners: [Banner] = []
}

在其他地方多次使用 BannerQueue.default 时发现 banners数组的值不一致,每次都是新建的数组。

查了下网上说结构体是值传递(在栈中),不能创建单例,每次调用都是一个新的对象,类才行(值引用, 在堆中)。

正确的单例方式:

class BannerQueue {
    
    static let `default` = BannerQueue()
     
    private init() {}   
}

注意: 必须保证init方法的私有性,只有这样,才能保证单例是真正唯一的,避免外部对象通过访问init方法创建单例类的其他实例。由于Swift中的所有对象都是由公共的初始化方法创建的,我们需要重写自己的init方法,并设置其为私有的。这很简单,而且不会破坏到我们优雅的单行单例方法。

以前在OC中创建单例,会用到dispatch_once,或者直接用OC的直接移植版写Swift单例, 其实没必要的,Swift这一句简洁的代码已经帮我们实现了dispatch_once,原因如下:

现在,你可能会有疑问:为何看不到dispatch_once?根据Apple Swift博客中的说法,以上方法都自动满足dispatch_once规则。这里有个帖子可以证明dispatch_once规则一直在起作用。
“全局变量(还有结构体和枚举体的静态成员)的Lazy初始化方法会在其被访问的时候调用一次。类似于调用'dispatch_once'以保证其初始化的原子性。这样就有了一种很酷的'单次调用'方式:只声明一个全局变量和私有的初始化方法即可。”--来自Apple's Swift Blog
(“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%安全的。

参考自:
Swift中编写单例的正确方式
Swift设计模式之单例(Singleton)

上一篇下一篇

猜你喜欢

热点阅读