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("Генерація звіту...")
return "Annual report data"
}()
}
let generator = ReportGenerator()
// звіт ще не створено на цьому етапі
print(generator.report) // "Генерація звіту..."
print(generator.report) // не перегенерується при наступних зверненнях
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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також