Lazy Property در Swift مکانیزم مقداردهی تأخیری است که در آن ویژگی در لحظه اولین دسترسی به آن محاسبه میشود، نه در زمان ایجاد شیء. برخلاف stored properties معمولی، متغیرهای تنبل به طور قابل توجهی زمان راهاندازی و مصرف حافظه را برای عملیاتهای سنگین کاهش میدهند. طبق Apple Developer Documentation (2026)، ویژگیهای تنبل تضمینشده فقط یک بار مقداردهی میشوند و در اولین دسترسی thread-safe هستند.
نکات اصلی
Lazy Property یک stored property است که مقداردهی آن تا اولین دسترسی به تأخیر میافتد. کلمه کلیدی lazy قبل از اعلان var به کامپایلر میگوید که مقدار را در زمان ایجاد شیء محاسبه نکند.
در حالت استاندارد، تمام stored properties در زمان ایجاد نمونه کلاس یا ساختار مقداردهی میشوند. اگر ویژگی نیاز به محاسبات پیچیده، بارگیری از شبکه یا کار با سیستم فایل داشته باشد، lazy اجازه میدهد این عملیات را تا زمانی که دادهها واقعاً مورد نیاز باشند به تأخیر بیندازید.
طبق Swift by Sundell (2025)، ویژگیهای تنبل یکی از مؤثرترین ابزارهای بهینهسازی عملکرد در برنامههای iOS هستند. آنها زمان راهاندازی را در برنامههای با راهاندازی اولیه سنگین، مانند ویرایشگرهای گرافیکی یا داشبوردهای تحلیلی، 20–40% کاهش میدهند.
اعلان ویژگی تنبل نیاز به کلمه کلیدی lazy قبل از var دارد. مقدار از طریق closure یا فراخوانی تابع تعیین میشود.
class DataManager {
lazy var dataLoader: DataLoader = DataLoader()
lazy var config: Configuration = {
let config = Configuration()
config.loadDefaults()
return config
}()
}
Closure برای ویژگی تنبل فقط یک بار محاسبه میشود و در دسترسیهای بعدی مقدار ذخیرهشده را برمیگرداند. این برای پیکربندی پیچیده با مراحل متعدد بسیار مناسب است.
class ImageCache {
lazy var cache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100
cache.totalCostLimit = 50 * 1024 * 1024
return cache
}()
}
چندین ویژگی تنبل مستقل از یکدیگر مقداردهی میشوند. اگر دو ویژگی تنبل از طریق closure به یکدیگر ارجاع دهند — یک وابستگی حلقوی ایجاد میشود که 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
ویژگیهای تنبل در زیرکلاسها بازنویسی نمیشوند. اگر کلاسی یک ویژگی تنبل اعلام کند، کلاس فرزند نمیتواند آن را به عنوان computed یا stored property با رفتار متفاوت بازنویسی کند.
طبق Apple Swift Blog (2025)، این محدودیت به این دلیل است که lazy یک اصلاحکننده بازنویسی نیست، بلکه جزئیات پیادهسازی ذخیرهسازی است. زیرکلاس فقط میتواند متدی را که ویژگی تنبل در closure فراخوانی میکند بازنویسی کند.
مقداردهی ویژگی تنبل در Swift thread-safe است: اگر دو نخ به طور همزمان به ویژگی تنبل دسترسی پیدا کنند، مقداردهی فقط یک بار انجام میشود، نخ دوم تا پایان آن مسدود میشود.
با این حال پس از مقداردهی، همگامسازی حذف میشود. این بدان معناست که خواندن همزمان از چندین نخ ایمن است، اما اگر یک نخ مقدار جدیدی در lazy var بنویسد و نخ دیگری بخواند — data race رخ میدهد.
طبق Swift Evolution proposal SE-0254 (2025)، مکانیزم همگامسازی ویژگیهای تنبل از طریق objc_sync_enter/exit در سطح پایین پیادهسازی شده است. این اتمی بودن مقداردهی را تضمین میکند، اما جهشهای بعدی را نه. برای کار ایمن با ویژگیهای mutable lazy از مکانیزمهای همگامسازی جداگانه استفاده کنید.
ویژگیهای تنبل در پروژههای 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)، ویژگیهای تنبل امکان سازماندهی مقداردهی عناصر UI را بدون شلوغ کردن init فراهم میکنند.
اولین محدودیت: lazy را نمیتوان با let استفاده کرد. ثابت باید قبل از اتمام init مقداردهی شود که با ایده مقداردهی تأخیری در تضاد است.
دومین محدودیت: lazy برای computed properties در دسترس نیست. Computed properties مقدار ذخیره نمیکنند، در حالی که lazy دقیقاً یک stored property با مقداردهی تأخیری است.
سومین محدودیت: ویژگیهای تنبل در structها میتوانند مشکلاتی با جهش ایجاد کنند. اگر struct با ویژگی تنبل به عنوان let اعلام شود، دسترسی به ویژگی غیرممکن است، زیرا مقداردهی نیاز به جهش struct دارد.
چهارمین: ویژگیهای تنبل willSet/didSet را در زمان مقداردهی فراخوانی نمیکنند. فقط در تغییرات بعدی، اگر ویژگی به عنوان var اعلام شده باشد.
طبق Stack Overflow (2025)، حدود 15% سؤالات مربوط به lazy با تلاش برای استفاده از lazy در زمینه let یا عدم درک یکبارگی مقداردهی مرتبط است. این محدودیتها در طراحی کلاسها مهم هستند.
سؤالات متداول
خیر، lazy فقط برای var در دسترس است. ثابتهای let باید قبل از اتمام init مقداردهی شوند که با مقداردهی تأخیری ناسازگار است.
دقیقاً یک بار. در اولین دسترسی ویژگی مقداردهی میشود، پس از آن مقدار ذخیرهشده را بدون محاسبه مجدد برمیگرداند.
مقداردهی thread-safe است — دو نخ ویژگی را دو بار مقداردهی نمیکنند. با این حال جهشهای بعدی به طور خودکار همگامسازی نمیشوند.
خیر، ویژگیهای تنبل بازنویسی نمیشوند. زیرکلاس فقط میتواند منطق داخل closure را تغییر دهد، اما نه خود مقداردهی تنبل را.
Lazy یک stored property است که یک بار محاسبه شده و مقدار را ذخیره میکند. Computed property در هر دسترسی محاسبه میشود و مقدار را ذخیره نمیکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید