Добавить объявление

Паттерны проектирования в Swift: Синглтон

Синглтон (Singleton) - это паттерн проектирования, который гарантирует, что у класса будет только один экземпляр на протяжении всего жизненного цикла приложения, и предоставляет к нему глобальную точку доступа.

Данный паттерн является одним из самых популярных и одновременно спорных паттернов в iOS разработке.

Вот как это работает на практике:


Когда вы создаёте синглтон, вы делаете его конструктор приватным, чтобы предотвратить создание дополнительных экземпляров извне, а единственный экземпляр храните в статическом свойстве. Swift автоматически обеспечивает ленивую инициализацию - объект создаётся только при первом обращении к этому свойству.

Например, если у вас есть класс AppConfig, который управляет настройками приложения, его можно реализовать как синглтон:

final class AppConfig {
static let shared = AppConfig()
private init() {}

var apiKey: String = "12345"
}

Такой подход удобен для объектов, которые должны быть доступны из разных частей программы, но при этом не должны дублироваться - например, для работы с настройками, сетевыми запросами или аналитикой.

В нашем коде есть серьезный недостаток, если в будущем понадобится подменить apiKey для тестов, возникнут сложности. Более гибкий вариант: использование протоколов:

protocol ConfigService {
var apiKey: String { get }
}

final class ProdConfig: ConfigService {
static let shared = ProdConfig()
private init() {}

let apiKey = "prod_12345"
}

class TestConfig: ConfigService {
let apiKey = "test_67890"
}

Теперь в проде используем ProdConfig.shared, а в тестах можем подсунуть объект TestConfig.

Главная проблема синглтонов:


Они создают неявные зависимости. Представьте, у вас 20 классов, использующих AppConfig.shared. Вдруг понадобится сделать разные конфиги для разных пользователей. Придется переписывать половину приложения.

Поэтому я использую синглтоны только для логгеров и аналитики. Для всего остального лучше подходит dependency injection, потому что это делает зависимости прозрачными и даёт гибкость в управлении объектами.

Пример:


protocol APIServiceProtocol {
func fetchData()
}

class APIService: APIServiceProtocol {
func fetchData() {
}
}

class DataManager {
let apiService: APIServiceProtocol

init(apiService: APIServiceProtocol) {
self.apiService = apiService
}

func loadData() {
apiService.fetchData()
}
}

Вывод:


Синглтон - мощный инструмент, но при неправильном использовании может принести больше вреда, чем пользы. Главная его опасность в том, что он создаёт скрытые зависимости, которые со временем превращают код в запутанный клубок. Лучше всего его использовать только для объектов, которые действительно должны существовать в единственном экземпляре.
31.07.2025 14 411