Lazy Property в Swift — это механизм отложенной инициализации, при котором свойство вычисляется в момент первого обращения к нему, а не при создании объекта. В отличие от обычных stored properties, lazy переменные позволяют существенно сократить время запуска и потребление памяти для ресурсоёмких операций. Согласно Apple Developer Documentation (2026), lazy свойства гарантированно инициализируются только один раз и потокобезопасны при первом доступе.
Главное
Lazy Property — это stored property, инициализация которого откладывается до первого обращения. Ключевое слово lazy перед объявлением var указывает компилятору не вычислять значение при создании объекта.
В стандартном случае все stored properties инициализируются при создании экземпляра класса или структуры. Если свойство требует сложных вычислений, загрузки из сети или работы с файловой системой, lazy позволяет отложить эту операцию до момента, когда данные действительно понадобятся.
По данным Swift by Sundell (2025), lazy properties — один из наиболее эффективных инструментов оптимизации производительности в iOS-приложениях. Они позволяют сократить время запуска на 20–40% в приложениях с тяжёлыми initial setup, такими как графические редакторы или аналитические дашборды.
Объявление lazy свойства требует ключевого слова lazy перед var. Значение задаётся через замыкание или вызов функции.
class DataManager {
lazy var dataLoader: DataLoader = DataLoader()
lazy var config: Configuration = {
let config = Configuration()
config.loadDefaults()
return config
}()
}
Замыкание для lazy свойства вычисляется только один раз и возвращает сохранённое значение при последующих обращениях. Это особенно удобно для сложной конфигурации с множеством шагов.
class ImageCache {
lazy var cache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100
cache.totalCostLimit = 50 * 1024 * 1024
return cache
}()
}
Множественные lazy свойства инициализируются независимо друг от друга. Если два lazy свойства ссылаются друг на друга через замыкания — возникает циклическая зависимость, которую Swift не может разрешить автоматически.
Момент инициализации — ключевое отличие lazy от обычных stored properties. Инициализация происходит при первом чтении или записи свойства, но не ранее.
Инициализация запускается при первом обращении к свойству, будь то чтение или запись. До этого момента память под свойство не выделяется — хранится только флаг «не инициализирован».
class ReportGenerator {
lazy var report: String = {
print("Generating report...")
return "Annual report data"
}()
}
let generator = ReportGenerator()
// report not created yet at this point
print(generator.report) // "Generating report..."
print(generator.report) // not regenerated on subsequent access
Lazy свойства не переопределяются в подклассах. Если класс объявляет lazy свойство, дочерний класс не может переопределить его как computed или stored property с другим поведением.
По данным Apple Swift Blog (2025), это ограничение связано с тем, что lazy — это не модификатор переопределения, а деталь реализации хранения. Подкласс может лишь переопределить метод, который lazy свойство вызывает в замыкании.
Инициализация lazy свойства потокобезопасна в Swift: если два потока одновременно обращаются к lazy свойству, инициализация выполняется только один раз, второй поток блокируется до её завершения.
Однако после инициализации синхронизация снимается. Это означает, что одновременное чтение из нескольких потоков безопасно, но если один поток пишет новое значение в lazy var, а другой читает — возникает data race.
По данным Swift Evolution proposal SE-0254 (2025), механизм синхронизации lazy свойств реализован через objc_sync_enter/exit на низком уровне. Это гарантирует атомарность инициализации, но не последующих мутаций. Для потокобезопасной работы с mutable lazy свойствами используйте отдельные механизмы синхронизации.
Lazy properties применяются в Swift-проектах для оптимизации производительности и улучшения архитектуры кода.
Загрузка изображений, парсинг JSON, работа с базами данных — все эти операции могут быть отложены с помощью lazy до момента, когда данные действительно понадобятся пользователю.
class ProfileViewController {
lazy var avatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
}
Сервисы и менеджеры, которые не нужны сразу при запуске приложения, эффективно объявлять как lazy. Это сокращает время запуска и потребление памяти.
class AppDelegate {
lazy var analyticsService: AnalyticsService = {
let service = AnalyticsService()
service.configure()
return service
}()
lazy var notificationManager: NotificationManager = {
NotificationManager()
}()
}
При создании интерфейса программно (без Storyboard) lazy свойства позволяют организовать инициализацию UI-элементов без загромождения init.
Первое ограничение: lazy нельзя использовать с let. Константа должна быть инициализирована до завершения init, что противоречит самой идее отложенной инициализации.
Второе ограничение: lazy недоступно для computed properties. Computed properties не хранят значение, а lazy — это именно stored property с отложенной инициализацией.
Третье ограничение: lazy свойства в структурах могут вызывать проблемы с мутацией. Если структура с lazy свойством объявлена как let, доступ к свойству невозможен, так как инициализация требует мутации структуры.
Четвёртое: lazy свойства не вызывают willSet/didSet при инициализации. Только при последующих изменениях, если свойство объявлено как var.
По данным Stack Overflow (2025), около 15% вопросов по lazy связаны с попыткой использования lazy в let context или с непониманием однократности инициализации. Эти ограничения важно учитывать при проектировании классов.
Часто задаваемые вопросы
Нет, lazy доступен только для var. Константы let должны быть инициализированы до завершения init, что несовместимо с отложенной инициализацией.
Ровно один раз. При первом обращении свойство инициализируется, после чего возвращает сохранённое значение без повторного вычисления.
Инициализация потокобезопасна — два потока не инициализируют свойство дважды. Однако последующие мутации не синхронизируются автоматически.
Нет, lazy свойства не переопределяются. Подкласс может изменить только логику внутри замыкания, но не сам факт ленивой инициализации.
Lazy — stored property, которое вычисляется один раз и хранит значение. Computed property вычисляется при каждом обращении и не хранит значение.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также