Lazy Property در Swift: چیست، سینتکس مقداردهی تنبل

نویسنده: IT Sectr منتشر شده: 2026-06-20 زمان مطالعه: 10 دقیقه

Lazy Property در Swift مکانیزم مقداردهی تأخیری است که در آن ویژگی در لحظه اولین دسترسی به آن محاسبه می‌شود، نه در زمان ایجاد شیء. برخلاف stored properties معمولی، متغیرهای تنبل به طور قابل توجهی زمان راه‌اندازی و مصرف حافظه را برای عملیات‌های سنگین کاهش می‌دهند. طبق Apple Developer Documentation (2026)، ویژگی‌های تنبل تضمین‌شده فقط یک بار مقداردهی می‌شوند و در اولین دسترسی thread-safe هستند.

نکات اصلی

  • Lazy — ویژگی در اولین دسترسی مقداردهی می‌شود، نه در زمان ایجاد شیء
  • فقط var — lazy برای let ممنوع است، زیرا ثابت باید قبل از مقداردهی شناخته شود
  • ایمنی نخ — مقداردهی ویژگی تنبل همگام‌سازی شده است، اما دسترسی مجدد — خیر
  • یکبارگی — lazy دقیقاً یک بار محاسبه می‌شود، دسترسی‌های بعدی مقدار ذخیره‌شده را برمی‌گردانند
  • بهینه‌سازی — زمان راه‌اندازی و مصرف حافظه را برای داده‌های کم‌استفاده کاهش می‌دهد

Lazy Property در Swift چیست؟

Lazy Property یک stored property است که مقداردهی آن تا اولین دسترسی به تأخیر می‌افتد. کلمه کلیدی lazy قبل از اعلان var به کامپایلر می‌گوید که مقدار را در زمان ایجاد شیء محاسبه نکند.

در حالت استاندارد، تمام stored properties در زمان ایجاد نمونه کلاس یا ساختار مقداردهی می‌شوند. اگر ویژگی نیاز به محاسبات پیچیده، بارگیری از شبکه یا کار با سیستم فایل داشته باشد، lazy اجازه می‌دهد این عملیات را تا زمانی که داده‌ها واقعاً مورد نیاز باشند به تأخیر بیندازید.

طبق Swift by Sundell (2025)، ویژگی‌های تنبل یکی از مؤثرترین ابزارهای بهینه‌سازی عملکرد در برنامه‌های iOS هستند. آنها زمان راه‌اندازی را در برنامه‌های با راه‌اندازی اولیه سنگین، مانند ویرایشگرهای گرافیکی یا داشبوردهای تحلیلی، 20–40% کاهش می‌دهند.

سینتکس ویژگی تنبل

اعلان ویژگی تنبل نیاز به کلمه کلیدی lazy قبل از var دارد. مقدار از طریق closure یا فراخوانی تابع تعیین می‌شود.

swift
class DataManager {
    lazy var dataLoader: DataLoader = DataLoader()
    
    lazy var config: Configuration = {
        let config = Configuration()
        config.loadDefaults()
        return config
    }()
}

Closure برای ویژگی تنبل فقط یک بار محاسبه می‌شود و در دسترسی‌های بعدی مقدار ذخیره‌شده را برمی‌گرداند. این برای پیکربندی پیچیده با مراحل متعدد بسیار مناسب است.

swift
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 معمولی است. مقداردهی در اولین خواندن یا نوشتن ویژگی رخ می‌دهد، اما نه زودتر.

اولین دسترسی (خواندن یا نوشتن)

مقداردهی در اولین دسترسی به ویژگی آغاز می‌شود، خواه خواندن باشد یا نوشتن. تا این لحظه حافظه برای ویژگی تخصیص داده نمی‌شود — فقط پرچم «مقداردهی نشده» ذخیره می‌شود.

swift
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 تا زمانی که داده‌ها واقعاً توسط کاربر مورد نیاز باشند به تأخیر بیفتند.

swift
class ProfileViewController {
    lazy var avatarImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        return imageView
    }()
}

وابستگی‌های Singleton

سرویس‌ها و مدیرانی که بلافاصله در راه‌اندازی برنامه نیاز نیستند، به طور مؤثر به عنوان lazy اعلام می‌شوند. این زمان راه‌اندازی و مصرف حافظه را کاهش می‌دهد.

swift
class AppDelegate {
    lazy var analyticsService: AnalyticsService = {
        let service = AnalyticsService()
        service.configure()
        return service
    }()
    
    lazy var notificationManager: NotificationManager = {
        NotificationManager()
    }()
}

کامپوننت‌های UI با کد

در ایجاد برنامه‌ریزی شده رابط (بدون 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 با let استفاده کرد؟

خیر، lazy فقط برای var در دسترس است. ثابت‌های let باید قبل از اتمام init مقداردهی شوند که با مقداردهی تأخیری ناسازگار است.

ویژگی تنبل چند بار محاسبه می‌شود؟

دقیقاً یک بار. در اولین دسترسی ویژگی مقداردهی می‌شود، پس از آن مقدار ذخیره‌شده را بدون محاسبه مجدد برمی‌گرداند.

آیا ویژگی تنبل در محیط چندنخی ایمن است؟

مقداردهی thread-safe است — دو نخ ویژگی را دو بار مقداردهی نمی‌کنند. با این حال جهش‌های بعدی به طور خودکار همگام‌سازی نمی‌شوند.

آیا می‌توان ویژگی تنبل را در زیرکلاس بازنویسی کرد؟

خیر، ویژگی‌های تنبل بازنویسی نمی‌شوند. زیرکلاس فقط می‌تواند منطق داخل closure را تغییر دهد، اما نه خود مقداردهی تنبل را.

تفاوت lazy با computed property چیست؟

Lazy یک stored property است که یک بار محاسبه شده و مقدار را ذخیره می‌کند. Computed property در هر دسترسی محاسبه می‌شود و مقدار را ذخیره نمی‌کند.

خلاصه

  • Lazy Property — مکانیزم مقداردهی تأخیری که در اولین دسترسی اجرا می‌شود
  • فقط var — lazy با let ناسازگار است، زیرا ثابت نیاز به مقداردهی فوری دارد
  • یکبارگی — مقداردهی یک بار انجام می‌شود، دسترسی‌های بعدی از مقدار ذخیره‌شده استفاده می‌کنند
  • ایمنی نخ — مقداردهی همگام‌سازی شده است، اما جهش‌های پس از مقداردهی نیاز به همگام‌سازی جداگانه دارند
  • کاربرد — منابع سنگین، کامپوننت‌های UI، سرویس‌های singleton، پیکربندی‌ها
  • محدودیت‌ها — نمی‌توان در let، computed properties، بازنویسی و struct با نمونه‌های let
  • بهینه‌سازی — زمان راه‌اندازی و مصرف حافظه را برای ویژگی‌های کم‌استفاده کاهش می‌دهد

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید