Swift单例与静态属性/方法

swi*_*one 4 singleton static swift

根据此博客文章以及对此Stack Overflow问题的最高投票答案该问题反过来引用了Apple的文档,在现代Swift中创建单例的最佳方法是:

class Singleton  {
   static let sharedInstance = Singleton()
}
Run Code Online (Sandbox Code Playgroud)

尽管未提及,但也可能需要使用a private init()

对我来说,一种更简单的选择是将所有属性和方法都转换为static,然后删除该sharedInstance属性。

例如,假设我按照上述建议编写了一个带有属性和方法的类,如下所示:

class Singleton {
  static let sharedInstance = Singleton("whatever")

  var myProperty: String

  func myMethod() {
    // ...
  }

  private init(_ myProperty) {
    self.myProperty = myProperty
  }
}
Run Code Online (Sandbox Code Playgroud)

如果用户需要访问所讨论的属性,则可以编写Singleton.sharedInstance.myProperty;如果需要调用方法,则可以编写Singleton.sharedInstance.myMethod()

我建议重写该类,如下所示:

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

  static func myMethod() {
    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

一个缺点是,与公正解决方案和之前的解决方案相比,从类内部对属性和方法的访问将需要完全阐明(Singleton.myPropertySingleton.myMethod())。myPropertymyMethod()

因此,这对用户来说比较容易(删除sharedInstance部分),对类编写者则有点困难(需要Singleton.在所有访问之前添加)。看起来很合理,当面对有利于用户或类编写器的设计选择时,更好的选择就是有利于用户。

似乎没有人提倡我提出的制作单身人士的方法,因此我感到它肯定有问题。有人会友善地指出这是什么吗?

Rob*_*ier 8

对我来说,一种更简单的选择是将所有属性和方法都转换为静态,然后删除sharedInstance属性。

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

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

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

如果环顾Cocoa,您会发现对于其他框架中的Singleton而言,共享实例非常普遍,而且功能非常强大。例如,已知有好NotificationCenterdefault,它可能是你曾经使用过的唯一一个。但是创建一个NotificationCenter独立的私有是完全有效的(我实际上已经在生产代码中做到了这一点)。

UIDevice.current是您访问设备而不是静态方法的事实,这使得可以处理多个设备的新API成为可能(这也有助于进行单元测试)。在最早的iOS版本中,唯一的UIScreen.main,因此将其设置为单例可能很有意义。但是因为Apple没有,所以在4.3中添加镜像时,谈论第二个屏幕(UIScreen.mirrored)很简单。通常,您应该非常缓慢地假设某物只能是其中之一。

  • 私有的“ init”允许将来扩展(例如,以后公开“ init”或创建子类),并且与所有其他对象的接口一致。调用者不必猜测某个东西是静态方法还是实例方法。除非它是* type *的基础(例如,工厂或默认值),否则方法应位于实例上。 (3认同)
  • 是的,多年来,关于名称的草率行事导致了各种不良模式。如此多的人复制了Apple过于复杂的“严格实施”示例,因为他们没有仔细阅读第一段:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects。 html#// apple_ref / doc / uid / TP40002974-CH4-SW32 (2认同)