Swift单例与静态属性/方法

时间:2019-01-25 17:22:41

标签: swift static singleton

根据this blog postcurrently highest voted answerthis 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)。在面对既有利于用户又有利于类编写器的设计选择时,似乎更好的选择就是有利于用户。

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

1 个答案:

答案 0 :(得分:5)

  

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

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

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

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

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

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