Я пытаюсь разработать подходящую модель синглтона для использования в Swift. До сих пор я смог получить не поточную модель, работающую как:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
}
if !Static.instance {
Static.instance = TPScopeManager()
}
return Static.instance!
}
}
Обтекание одноэлементного экземпляра в структуре Static должно позволять одному экземпляру, который не сталкивается с одноэлементными экземплярами, без сложных схем именования, и это должно делать вещи довольно частными. Очевидно, что эта модель не является поточно-ориентированной. Поэтому я попытался добавить dispatch_once
ко всему этому:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
static var token: dispatch_once_t = 0
}
dispatch_once(Static.token) { Static.instance = TPScopeManager() }
return Static.instance!
}
}
Но я получаю сообщение об ошибке компилятора dispatch_once
:
Невозможно преобразовать тип выражения 'Void' в тип '()'
Я пробовал несколько разных вариантов синтаксиса, но все они, похоже, имеют одинаковые результаты:
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
Как правильно использовать dispatch_once
Swift? Сначала я думал, что проблема с блоком из- ()
за сообщения об ошибке, но чем больше я на него смотрю, тем больше думаю, что это может быть вопросом dispatch_once_t
правильного определения.
@lazy
должна быть поточно-ориентированной.Static.instance = TPScopeManager()
заставляет тип экземпляра. Если вы используете что-то вродеStatic.instance = self()
обязательного инициализатора, будет создан соответствующий класс типов. Тем не менее, и это важно отметить, только один раз для всех случаев в иерархии! Первый тип для инициализации - это тип, установленный для всех экземпляров. Я не думаю, что цель-c вела себя так же.Ответы:
tl; dr: используйте подход с константой класса, если вы используете Swift 1.2 или выше и вложенную структуру подход если вам нужно поддерживать более ранние версии.
Из моего опыта работы со Swift есть три подхода к реализации шаблона Singleton, которые поддерживают отложенную инициализацию и безопасность потоков.
Константа класса
Этот подход поддерживает ленивую инициализацию, потому что Swift лениво инициализирует константы класса (и переменные) и является потокобезопасным по определению
let
. Это официально рекомендованный способ создания экземпляра синглтона.Классовые константы были введены в Swift 1.2. Если вам требуется поддержка более ранней версии Swift, используйте подход с вложенной структурой ниже или глобальную константу.
Вложенная структура
Здесь мы используем статическую константу вложенной структуры в качестве константы класса. Это обходной путь для отсутствия статических констант класса в Swift 1.1 и более ранних версиях, и все еще работает как обходной путь для отсутствия статических констант и переменных в функциях.
dispatch_once
Традиционный подход Objective-C перенесен на Swift. Я почти уверен, что нет преимущества над подходом с вложенными структурами, но я все равно привожу его здесь, так как нахожу различия в синтаксисе.
Смотрите этот проект GitHub для модульных тестов.
источник
init
ли быть объявленыprivate
также гарантии того, что один и только один экземпляр объекта будет существовать в течение всего времени жизни приложения?final
чтобы вы не делили его на подклассы; и (б) объявлениеinit
методаprivate
так, что вы не можете случайно создать экземпляр другого экземпляра где-либо.Поскольку Apple уже пояснила, что статические переменные структуры инициализируются как ленивые, так и обернутые
dispatch_once
(см. Примечание в конце статьи), я думаю, что мое окончательное решение будет таким:Это использует преимущества автоматической ленивой поточно-ориентированной инициализации статических элементов структуры, надежно скрывает фактическую реализацию от потребителя, сохраняет все компактно разделенными для удобочитаемости и устраняет видимую глобальную переменную.
Apple уточнила, что ленивый инициализатор является поточно-ориентированным, поэтому нет необходимости в
dispatch_once
подобных защитахОт сюда
источник
private init() {}
для дальнейшего обеспечения того факта, что этот класс не предназначен для внешнего применения.Для Swift 1.2 и выше:
С доказательством правильности (весь кредит идет сюда ), там практически нет причин теперь использовать любого из предыдущих методов для одиночек.
Обновление : теперь это официальный способ определения синглетонов, как описано в официальных документах. !
Что касается опасений по поводу использования
static
противclass
.static
должен использоваться один раз, когдаclass
переменные становятся доступными. Синглтоны не должны быть разделены на подклассы, так как это приведет к нескольким экземплярам базового синглтона. С помощьюstatic
обеспечивает это красивым, быстрым способом.Для Swift 1.0 и 1.1:
С недавними изменениями в Swift, в основном новыми методами контроля доступа, я теперь склоняюсь к более чистому способу использования глобальной переменной для синглетонов.
Как упомянуто в статье блога Swift здесь :
Этот способ создания синглтона является потокобезопасным, быстрым, ленивым, а также подключается к ObjC бесплатно.
источник
private init() {}
качестве инициализатораSingletonClass
. чтобы предотвратить создание экземпляра снаружи.Swift 1.2 или новее теперь поддерживает статические переменные / константы в классах. Так что вы можете просто использовать статическую константу:
источник
Есть лучший способ сделать это. Вы можете объявить глобальную переменную в вашем классе над объявлением класса следующим образом:
Это просто вызывает вашу стандартную инициализацию или любую другую инициализацию и глобальные переменные
dispatch_once
по умолчанию в Swift. Затем в любом классе вы хотите получить ссылку, вы просто делаете это:Таким образом, вы можете избавиться от всего блока общего кода экземпляра.
источник
TPScopeManager.sharedInstance.doIt()
все время, просто назовите свой классTPScopeManagerClass
, поместите это объявление рядом с классомpublic let TPScopeManager = TPScopeManagerClass()
, а при использовании - просто пишитеTPScopeManager.doIt()
. Очень чистый!TPScopeManager
, и поэтому оно не является единичным по определению.Swift одиночки подвергаются в рамках какао в качестве класса функций, например
NSFileManager.defaultManager()
,NSNotificationCenter.defaultCenter()
. Поэтому в качестве функции класса имеет больше смысла отражать это поведение, а не переменную класса, как некоторые другие решения. например:Получить синглтон через
MyClass.sharedInstance()
.источник
static
свойствами.Согласно документации Apple , много раз повторялось, что самый простой способ сделать это в Swift - использовать свойство статического типа:
Однако, если вы ищете способ выполнить дополнительную настройку помимо простого вызова конструктора, секрет состоит в том, чтобы использовать немедленно вызванное замыкание:
Это гарантированно поточно-ориентировано и лениво инициализируется только один раз.
источник
Свифт 4+
источник
Глядя на пример кода Apple, я наткнулся на этот шаблон. Я не уверен, как Swift справляется со статикой, но это будет поточно-ориентированным в C #. Я включаю и свойство и метод для взаимодействия Objective-C.
источник
dispatch_once
материалы. Я делаю ставку на ваш стиль. :)class
в объявлении класса нет эквивалентаstatic
в объявлении структуры?dispatch_once
возможность полезна как глобальным, так и статическим членам структур и перечислений .Вкратце,
Вы можете прочитать файлы и инициализация
источник
Если вы планируете использовать свой одноэлементный класс Swift в Objective-C, эта настройка заставит компилятор генерировать соответствующие заголовки (-и), подобные Objective-C:
Затем в классе Objective-C вы можете назвать свой синглтон так, как вы это делали в пред-Свифтские дни:
Это просто моя простая реализация.
источник
NSFileManager.defaultManager()
, но до сих пор использует ленивые механизмы статического члена поточно-Свифт.Первое решение
Позже в вашем коде:
Второе решение
И позже в вашем коде вы сможете сохранить скобки для меньшего количества путаницы:
источник
Тогда назови это;
источник
init
какprivate
, но и для того, чтобы сделатьsharedMyModel
какfinal
! Ради будущих читателей, в Swift 3 мы можем быть склонны переименоватьsharedMyModel
в «просто»shared
.Использование:
Как пользоваться:
источник
Лучший подход в Swift выше 1.2 - это однострочный синглтон, так как -
Чтобы узнать больше об этом подходе вы можете посетить эту ссылку .
источник
NSObject
подкласс? Кроме того, это похоже на то же самое, что и stackoverflow.com/a/28436202/1187415 .Из Apple Docs (Swift 3.0.1),
источник
Я бы предложил
enum
, как вы бы использовали в Java, напримеристочник
Просто для справки, вот пример реализации Singleton реализации Nested Struct Джека Ву / hpique. Реализация также показывает, как может работать архивирование, а также некоторые сопутствующие функции. Я не мог найти это полный пример, так что, надеюсь, это кому-нибудь поможет!
И если вы не узнали некоторые из этих функций, вот небольшой живой служебный файл Swift, который я использовал:
источник
В swift вы можете создать одноэлементный класс следующим образом:
источник
Я предпочитаю эту реализацию:
источник
Мой способ реализации в Swift ...
ConfigurationManager.swift
Доступ к globalDic с любого экрана приложения по нижеуказанному.
Читать:
Написать:
источник
Единственный правильный подход ниже.
Доступ
Причины:
static
Свойство type гарантированно будет инициализироваться лениво только один раз, даже при одновременном доступе к нескольким потокам, поэтому нет необходимости использоватьdispatch_once
init
метода, поэтому экземпляр не может быть создан другими классами.final
класс, поскольку вы не хотите, чтобы другие классы наследовали класс Singleton.источник
static let sharedInstance = Singleton()
После просмотра реализации Дэвида кажется, что нет необходимости иметь функцию синглтон-класса,
instanceMethod
такlet
как он выполняет почти то же самое, что иsharedInstance
метод класса. Все, что вам нужно сделать, это объявить его как глобальную константу, и это будет так.источник
источник
dispatch_once
так как инициализация статических переменных ленива и автоматически защищена черезdispatch_once
Apple, фактически рекомендует использовать статику вместо dispatch_once по этой причине.Быстрая реализация синглтона в прошлом - это не что иное, как три способа: глобальные переменные, внутренние переменные и способы dispatch_once.
Вот два хороших синглтона. (Примечание: независимо от того, какой вид написания должен обращать внимание на метод приватизации init (). Так как в Swift все конструкторы объекта по умолчанию являются публичными, их нужно переписать, init можно превратить в приватный , запретить другим объектам этого класса '()' по умолчанию метод инициализации для создания объекта.)
Способ 1:
Способ 2:
источник
Это самый простой с поточно-ориентированными возможностями. Никакой другой поток не может получить доступ к одному и тому же объекту-одиночке, даже если он хочет. Свифт 3/4
источник
Мне требовался мой синглтон, чтобы разрешить наследование, и ни одно из этих решений фактически не позволяло это. Итак, я придумал это:
Singleton.sharedInstance()
первом выполнении он вернет экземплярSingleton
SubSingleton.sharedInstance()
первом выполнении он вернет экземплярSubSingleton
созданного.SubSingleton.sharedInstance()
этоSingleton
верно и используется тот же экземпляр.Проблема с этим первым грязным подходом заключается в том, что я не могу гарантировать, что подклассы будут реализовывать
dispatch_once_t
и что онsharedInstanceVar
будет изменен только один раз для каждого класса.Я постараюсь уточнить это дальше, но было бы интересно узнать, есть ли у кого-то сильные чувства против этого (помимо того, что он многословен и требует его обновления вручную).
источник
Это моя реализация. Это также не позволяет программисту создавать новый экземпляр:
источник
private init
было уже предложено здесь: stackoverflow.com/a/28436202/1187415 .Я использую следующий синтаксис:
Это работает от Swift 1.2 до 4 и имеет несколько преимуществ:
Singleton.instance
источник