根据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
和{{1相比,从类内部对属性和方法的访问将需要被完全阐明(Singleton.myMethod()
和myProperty
)。 }}用于以前的解决方案。
因此,这对用户来说稍微容易一些(删除myMethod()
部分),对类编写器则有点困难(需要在所有访问之前添加sharedInstance
)。在面对既有利于用户又有利于类编写器的设计选择时,似乎更好的选择就是有利于用户。
似乎没有其他人拥护我提出的制作单身人士的方法,因此我感到它肯定有问题。有人会友善地指出这是什么吗?
答案 0 :(得分:5)
对我来说,一种更简单的选择是将所有属性和方法都转换为静态,然后删除sharedInstance属性。
这些不做相同的事情。推荐的方法实际上根本不是单例。这只是一个众所周知的实例。 Singleton模式的概念是,必须只能是一个实例。共享实例模式的共同点是可以有多个实例,但是您可能想要一个实例,并且您希望可以轻松访问它。
共享实例的优点是它们不是神奇的。它们只是实例。这意味着它们可以作为值传递。可以将它们替换为可能配置不同的其他实例。它们更易于测试(因为它们可以传递给函数)。
真正的单例是一个非常严格的模式,仅在绝对必要不存在其他实例时才应使用,通常是因为它们与某些外部唯一资源交互,如果存在多个实例,则会产生冲突(这很漂亮)罕见)。即使在这种情况下,在Swift中,通常也应该将init
设为私有,以防止创建其他实例。
如果环顾Cocoa,您会发现对于其他框架中的Singleton而言,共享实例非常普遍,而且功能非常强大。例如,有一个众所周知的NotificationCenter
,叫做default
,它可能是您曾经使用过的唯一一个。但是创建独立的私有NotificationCenter
是完全有效的(我实际上已经在生产代码中做到了这一点)。
UIDevice.current
是您访问设备而不是静态方法的事实,这使得可以处理多个设备的新API成为可能(这也有助于进行单元测试)。在最早的iOS版本中,唯一的UIScreen
是.main
,将其设为单例可能是有意义的。但是由于Apple没有,因此在4.3中添加镜像时,谈论第二个屏幕(UIScreen.mirrored
)很简单。通常,您应该非常缓慢地假设某物只能是其中之一。