根据 this blog post和 currently highest voted answer至 this Stack Overflow question ,它又引用了 Apple's documentation ,在现代 Swift 中创建单例的最佳方式是:
class Singleton {
static let sharedInstance = Singleton()
}
虽然没有提到,但可能还需要一个 private init()
。
对我来说,一个更简单的替代方法是将所有属性和方法转换为 static
,并删除 sharedInstance
属性。
例如,假设我按照上面的建议编写了一个带有属性和方法的类,如下所示:
class Singleton {
static let sharedInstance = Singleton("whatever")
var myProperty: String
func myMethod() {
// ...
}
private init(_ myProperty) {
self.myProperty = myProperty
}
}
如果用户需要访问有问题的属性,他们会写Singleton.sharedInstance.myProperty
,如果他们需要调用方法,他们会写Singleton.sharedInstance.myMethod ()
。
我建议重写类如下:
class Singleton {
static var myProperty: String = "whatever"
static func myMethod() {
// ...
}
}
因此:样板代码更少,访问属性(仅 Singleton.myProperty
)和方法(Singleton.myMethod()
)时输入的字符也更少。
一个缺点是,从类内部访问属性和方法需要完整拼写(Singleton.myProperty
和 Singleton.myMethod()
),与之前解决方案的 myProperty
和 myMethod()
相比。
因此,这对用户来说更容易一些(删除 sharedInstance
部分),对类编写者来说更难一些(需要添加 Singleton.
在所有访问的前面)。这似乎是合理的,当面临有利于用户或类作者的设计选择时,更好的选择是有利于用户。
似乎没有人提倡我提出的创建单例的方法,所以我觉得它一定有问题。有好心人指点一下是什么吗?
最佳答案
To me, a simpler alternative would be to convert all properties and methods to static, and drop the sharedInstance property.
这些不做同样的事情。推荐的方法实际上根本不是单例。这只是一个众所周知的例子。单例模式的概念是必须只有一个实例。共享实例模式的特点是可以有多个实例,但您可能需要一个实例,并且您希望轻松访问它。
共享实例的优点是它们并不神奇。他们只是个例。这意味着它们可以作为值传递。它们可以替换为可能配置不同的其他实例。它们更容易测试(因为它们可以传递到函数中)。
真正的单例是一种非常严格的模式,只有在绝对必要不存在其他实例时才应使用,通常是因为它们与某些外部唯一资源交互的方式会在存在多个时产生冲突(这很漂亮稀有的)。即使在这种情况下,在 Swift 中,您通常也应该将 init
设为私有(private),以防止创建其他实例。
如果您环顾 Cocoa,您会发现共享实例对于在其他框架中可能是单例的事物极为常见,而且这非常强大。例如,有一个众所周知的 NotificationCenter
叫做 default
,它可能是您唯一用过的。但是创建一个独立的私有(private) NotificationCenter
是完全有效的(我实际上已经在生产代码中这样做了)。
UIDevice.current
是您访问设备的方式,而不是静态方法,这一事实为可以处理多个设备的新 API 提供了可能性(它也有助于单元测试)。在最早的 iOS 版本中,唯一的 UIScreen
是 .main
,将其设为单例可能更有意义。但是因为苹果没有,所以在4.3加入镜像的时候,就简单的说说副屏(UIScreen.mirrored
)。通常,您应该非常缓慢地假设某物只能存在其中之一。
关于Swift 单例与静态属性/方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54370045/