Синглтон-класс может быть создан без использования «Static»? - PullRequest
0 голосов
/ 05 июня 2019

Мы используем Static для объявления singleton, поэтому будет создан только один экземпляр.Можно ли объявить синглтон без использования Static?Если да, можно ли переопределить экземпляр?

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

1 Ответ

2 голосов
/ 05 июня 2019

Здесь много проблем, поэтому сначала разберемся с ними:

  1. Это недействительный код Swift. Class и Static оба должны быть в нижнем регистре.
  2. Имена типов в Swift должны быть UpperCamelCase.
  3. Форматирование все шаткое.

Исправляя это, мы получаем:

class SingletonClass {
    static let shared = SingletonClass()

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

То, что у вас здесь есть, это общий экземпляр, но на самом деле это не одиночка. Ключевой характеристикой синглтона является то, что он ... одиночный. Это совсем не так, потому что абсолютно ничто не мешает мне сказать:

let myOwnInstance = SingletonClass()

Синглтоны обычно используются для моделирования состояния единственного физического ресурса. Если существуют два экземпляра, они могут мешать друг другу. Рассмотрим этот пример (дефектного) синглтона, который пытается смоделировать один светодиод на аппаратном обеспечении:

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 для проверка состояния. При таких обстоятельствах вашей программе необходимо запоминать состояние, сохраняя его в переменной и обеспечивая постоянное обновление «запомненного состояния» и реального оборудования.

Эта реализация гарантирует, что все сделано правильно, потому что turnLEDOn и turnLEDOff могут быть вызваны только с помощью мутации 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)
    }
}

Но вам нужна какая-то форма статического хранилища (глобальная переменная, статическое хранилище, хранилище классов). Хранилище экземпляров (хранимые свойства) фактически не выделяет память, если нет экземпляра. А поскольку нет экземпляра для хранения синглтон-ссылки, это не имеет смысла.

...