Приведи пример реализации паттерна Singleton в UIKit или Foundation
Что проверяют
Знаете ли вы синглтоны платформы и умеете ли написать свой без лишнего. Заодно интервьюер смотрит, понимаете ли вы, что именно в Swift гарантирует однократную инициализацию и где эта гарантия заканчивается.
Как отвечать
Сначала назовите штатные примеры: UIApplication.shared, UserDefaults.standard, FileManager.default, NotificationCenter.default, URLSession.shared, Bundle.main. Потом покажите свой:
final class AnalyticsService {
static let shared = AnalyticsService()
private init() {}
}Объясните каждую строку. static let в Swift инициализируется лениво и ровно один раз, под капотом однократный вызов, поэтому dispatch_once из времён Objective-C тут не нужен. private init закрывает создание вторых экземпляров, final закрывает наследование.
Дальше самое важное: потокобезопасна только инициализация, а не сам объект. Если внутри есть изменяемое состояние, защищайте доступ явно: последовательная очередь, NSLock или актор.
actor AnalyticsService {
static let shared = AnalyticsService()
private var events: [String] = []
func track(_ name: String) { events.append(name) }
}Хорошо закончить ценой паттерна: синглтон это глобальное состояние, которое нельзя подменить в тесте, если тянуть .shared прямо из кода. Практика: принимать зависимость в инициализаторе, а .shared подставлять значением по умолчанию.
Где спотыкаются
Пишут static var shared и оставляют публичный инициализатор. Экземпляр можно подменить снаружи и создать второй, то есть от паттерна остаётся одно название.
Считают, что static let делает потокобезопасным весь объект. Гарантия касается только создания: словарь внутри общего экземпляра при записи из двух потоков спокойно портится или роняет приложение.
Тянут .shared прямо в модели и контроллеры. Тесты начинают влиять друг на друга через общее состояние, порядок запуска становится важен, и один упавший тест роняет соседние.