Синглтон на Swift, или как правильно написать Singleton

Для написания Синглтона (Singleton) на языке Swift можно использовать несколько подходов. Теоретически — все будут работать, однако надо бы до конца разобраться какой же вариант является правильным с точки зрения работы и написания кода.

Для этого давайте разберем что делает Синглтон Синглтоном.

Я не буду вдаваться в подробности зачем вообще нужен Singleton и как его использовать, — это не является темой для этой статьи. А вот синтаксис написания — мы разберем подробно, от исторического определения на Objective-C до современного Swift 2.1

Есть по существу три параметра или свойства (кому как удобно), которыми должен обладать Singleton:

  • Singleton должен быть уникальным. У Этого класса может быть только один экземпляр для всего жизненного цикла приложения, в котором он существует. Singleton создается для отслеживания какого либо глобального состояния, например для подсчета игровых очков в игре. Также хорошие и известные начинающим программистам примеры экземпляры классов NSNotificationCenter, UIApplication  и NSUserDefaults.
  • Из правила №1,  следует для того, чтобы иметь только один экземпляр на протяжении всего жизненного цикла приложения, класс Singleton должен быть потоко-безопасным. При использовании мультизадачности (multithreading)  и программировании в нескольких потоках, следует внимательно следить за созданием экземпляров класса, который будет Сингтоном. Проще говоря, если Singleton неправильно описан в коде,  то может возникнуть ситуация с двумя параллельными потоками, которые пытаются инициализировать Singleton в одно и то же время. В результате потенциально могут получится два отдельных экземпляра Singleton. Т.е. мы должны обернуть инициализацию класса  в dispatch_once блок от GCD, чтобы убедиться, код инициализации работает только один раз во время выполнения.
  • Для поддержания уникальности Singleton инициализатор синглтона должен быть private. Это позволит предотвратить создание экземпляров вашего Singeton другими объектами.

Начнем издалека: давайте вспомним как инициализация Singleton выглядела при написании на языке программирования Objective-C

Это все великолепно работает, но мы же собрались рассматривать реализацию на Swift!  С самого начала могу сказать что Swift позволяет сделать четыре реализации нашей задачи, все четыре вариации я опишу в этой статье, и только последняя будет элегантной и полностью функциональной. Так что если вы не хотите читать как я растекаюсь мыслю по веб-странице можете прокрутить ее вниз и увидеть нужный кусок кода.

  1. Итак первый вариант — это запись кода на Objective-C языком Swift:

Как было указано ранее, — этот вариант — это портирование кода из начала статьи.

2) Второй вариант — это запись с использованием статичной структуры.

Тут надо учитывать, что  Swift 1.0, не поддерживал статические переменные класса. Однако, в структурах их можно было использовать! Из-за этих ограничений на статические переменные, программисты были вынуждены использовать модели подобные этой. Это лучше, чем прямой Objective-C порт, но все еще не достаточно хорошо.

3) Третий вариант — установка глобальной переменной

В Swift 1.2, были добавлены спецификаторы контроля доступа и возможность использования статических членов класса. Это означало, что более нет необходимости использовать глобальную переменную, и соответственно иметь беспорядок в глобальном пространстве имен.

Сейчас на этом месте, внимательный читатель может спросить,  почему мы не использовали dispatch_once в наших реализациях структур или глобальных переменных? Ответ на этот вопрос нам дает Swift Блог Apple:

The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic. This enables a cool way to use dispatch_once in your code: just declare a global variable with an initializer and mark it private.

То есть Apple утверждает, что если создать глобальную переменную и ее инициализатор сделать private, то за кулисами языка инициализация оборачивается в блок dispatch_once при доступе в глобальное пространство.

Финальный рабочий вариант

Ну и в конце концов мы подошли к четвертому варианту определения Singleton, и это будет вариант описания одной строкой!

Для доказательства того, что такая конструкция работает и работает верно можно собрать небольшой проект, и расставить точки останова в компиляторе. Следующую статью я посвящу именно этому.

Да! Язык Swift предоставляет весьма элегантные решения для тривиальных и не очень задач. Именно поэтому программисты которые решили освоить программирование iOS и Mac выбирают именно это язык программирования.

Опубликовано в Iron ribbon, Реальные примеры, Фундаментальные основы Метки: ,
2 комментария на “Синглтон на Swift, или как правильно написать Singleton
  1. fmaxx:

    А что если в последнем варианте мы можем просто сделать
    let anotherInstance =OnlyOneST()
    и получается у нас 2 экземпляра класса OnlyOneST ?

    • admin:

      Инициализацию Sigletone нужно производить
      let istance = OnlyOneST().sharedInstance

      и тогда
      let anotherIstance = OnlyOneST().sharedInstance

      будет ссылаться на тот же объект.

      А чтобы быть правильным до конца, нужно инициализатор для класса пометить private:
      private init() {
      }

      И тогда на строке
      let anotherIstance = OnlyOneST()
      компилятор выдаст ошибку.

      У меня уже почти готова статья про Singlton как шаблон программирования. В ней будет приведен пример создания Singleton на Swift в стиле Apple, как, допустим, в NSUserDefaults или UIApplicaton. В ней будет описан метод более привычного использования этого шаблона.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*