不使用'Static'也能创建单例class?

Singleton class can be created without using 'Static'?

我们使用Static声明singleton所以只会创建一个实例。是否可以在不使用 Static 的情况下声明单例?如果是,是否可以覆盖实例?

class SingletonClass {
    static let shared = SingletonClass();
    func requestToAccess() {
        // Print statement
    }
}

这里有很多问题,所以让我们先解决这些问题:

  1. 这是无效的 Swift 代码。 ClassStatic 都必须小写。
  2. Swift 中的类型名称应为 UpperCamelCase。
  3. 格式全都不对。

解决这个问题,我们得到:

class SingletonClass {
    static let shared = SingletonClass()

    func requestToAccess() {
        print(SingletonClass.shared)
    }
}

你这里有一个共享实例,但实际上不是单例。单身人士的关键定义特征是它很好......单身。这里完全不是这种情况,因为绝对没有什么能阻止我说:

let myOwnInstance = SingletonClass()

单例通常用于为单个物理资源的状态建模。如果存在两个实例,它们可能会相互干扰。考虑这个例子,一个(有缺陷的)单例试图在一块硬件上模拟单个 LED:

public class UserActivityIndicatorLED {
    public static let shared = UserActivityIndicatorLED()

    public private(set) var currentState: Bool = false {
        didSet {
            if currentState { turnLEDOn() }
            else { turnLEDOff() }
        }
    }

    public func toggle() { self.currentState.toggle() }
}

"write-only" 事物存在的情况并不少见,其中您有一个 API 用于设置值(例如微型数字输出引脚的 on/off 状态控制器),但没有相应的 API 用于检查状态。在这种情况下,您的程序需要通过将状态保存到变量来记住状态,并确保 "remembered state" 和真实硬件始终一起更新。

此实现确保正确完成,因为 turnLEDOnturnLEDOff 只能通过改变 currentState 来调用。但是,由于违反了单例属性,因此可能会发生这种情况:

UserActivityIndicatorLED.shared().toggle() // => UserActivityIndicatorLED.shared().currentState becomes true, LED turns on

let myInstance = UserActivityIndicatorLED() // => I create a new instance, violating the singleton pattern
myInstance.toggle() // myInstance.currentState becomes true, LED is made to turn on again (it just stays on)
myInstance.toggle() // myInstance.currentState becomes false, LED is turned off, but UserActivityIndicatorLED.shared().currentState is still true!


// Now the system's "memory" of the physical state is desynchronized from the
// "true hardware" state, because creating a new instance of `UserActivityIndicatorLED`
// permitting the mutation of the hardware state without a corresponding update to the
// memorized state.
// Some user calls this again, expecting the LED to turn off, but surprise, it's already off!
UserActivityIndicatorLED.shared().toggle() // UserActivityIndicatorLED.shared().currentState becomes false, but the light was already off

要解决此问题,并确保您 实际上 有一个单例,需要将初始化程序设为私有,以便只能在 SingletonClass 内创建新实例,因此对初始化程序的唯一调用是 shared 变量:

class SingletonClass {
    static let shared = SingletonClass()

    private init() { }

    func requestToAccess() {
        print(SingletonClass.shared)
    }
}

我需要使用静态变量吗?

不一定,你可以使用全局变量,但那更糟:

let SingletonClassShared = SingletonClass()

class SingletonClass {
    fileprivate init() { }

    func requestToAccess() {
        print(SingletonClass.shared)
    }
}

但是您确实需要某种形式的静态存储(全局变量、静态存储、class 存储)。除非有一个实例,否则实例存储(存储属性)实际上并不分配内存。而且由于没有实例来存储单例引用,所以它没有任何意义。