是否可以在不使用“静态”的情况下创建Singleton类?

时间:2019-06-05 12:05:32

标签: swift static singleton

我们使用Static来声明singleton,因此将仅创建一个实例。是否可以在不使用Static的情况下声明单例?如果是,实例是否可以被覆盖?

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

1 个答案:

答案 0 :(得分:2)

这里有很多问题,所以让我们先清除一下这些问题:

  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() }
}

存在“仅写”内容的情况并不少见,其中您具有用于设置值的API(例如,微控制器的数字输出引脚的开/关状态),但没有相应的API用于检查状态。在这种情况下,您的程序需要通过将状态保存为变量来记住状态,并确保“记住的状态”和实际硬件始终一起更新。

此实现可确保正确完成,因为turnLEDOnturnLEDOff仅可通过对currentState进行更改来调用。但是,由于违反了singleton属性,因此可能会发生:

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)
    }
}

但是您需要某种形式的静态存储(全局变量,静态存储,类存储)。除非有实例,否则实例存储(存储的属性)实际上不会分配内存。而且,由于没有实例可以存储单例引用,因此这没有任何意义。