Swift 单例与静态 properties/methods

Swift singleton vs. static properties/methods

根据this blog post and the currently highest voted answer to this Stack Overflow question, which in turn cites Apple's documentation,在现代Swift中创建单例的最佳方法是:

class Singleton  {
   static let sharedInstance = Singleton()
}

虽然没有提到,但可能也需要 private init()

对我来说,一个更简单的替代方法是将所有属性和方法转换为 static,然后删除 sharedInstance 属性.

例如,假设我按照上面的建议写了一个class和一个属性和一个方法,如下:

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 如下:

class Singleton {
  static var myProperty: String = "whatever"

  static func myMethod() {
    // ...
  }
}

因此:样板代码更少,访问 属性(仅 Singleton.myProperty)和方法(Singleton.myMethod())时输入的字符也更少。

一个缺点是从 class 内部访问 属性 和方法需要完整拼写(Singleton.myPropertySingleton.myMethod()),相比之下前面的解决方案只有 myPropertymyMethod()

因此,这对用户来说更容易一些(删除 sharedInstance 部分),对 class 编写者来说更难一些(需要在前面添加 Singleton.所有访问)。这似乎是合理的,当面临有利于用户或 class 作者的设计选择时,更好的选择是有利于用户。

似乎没有人提倡我提出的制作单例的方法,所以我觉得它一定有问题。有好心人指点一下是什么吗?

To me, a simpler alternative would be to convert all properties and methods to static, and drop the sharedInstance property.

这些不做同样的事情。推荐的方法实际上根本不是单例。这只是一个众所周知的例子。单例模式的概念是必须只有一个实例。共享实例模式的共同点是可以有多个实例,但您可能想要一个,并且您希望轻松访问它。

共享实例的优点是不神奇。他们只是个例。这意味着它们可以作为值传递。它们可以替换为可能配置不同的其他实例。它们更容易测试(因为它们可以传递到函数中)。

真正的单例是一种非常严格的模式,只有在绝对必要不存在其他实例时才应使用,通常是因为它们与某些外部唯一资源交互的方式会在存在多个时产生冲突(这非常罕见)。即使在这种情况下,在 Swift 中,您通常也应该将 init 设为私有以防止创建其他实例。

如果您环顾四周 Cocoa,您会发现共享实例对于在其他框架中可能是单例的事物极为常见,而且这非常强大。例如,有一个众所周知的 NotificationCenter 叫做 default,它可能是您使用过的唯一一个。但是创建一个独立的私有 NotificationCenter 是完全有效的(我实际上已经在生产代码中这样做了)。

事实上 UIDevice.current 是您访问设备的方式,而不是静态方法,这为可以处理多个设备的新 API 提供了可能性(它也有助于单元测试)。在 iOS 的最早版本中,唯一的 UIScreen.main,将其设为单例可能更有意义。但是因为苹果没有,所以在4.3加入镜像的时候,简单的说说副屏(UIScreen.mirrored)。你通常应该很慢地假设某事只能是其中之一。