willSet و didSet در Swift: چیست، Syntax و نحوه کار ناظران

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

willSet و didSet ناظران ویژگی (property observers) در Swift هستند که به شما امکان می‌دهند قبل و بعد از تغییر مقدار ویژگی کد اجرا کنید. برخلاف computed properties، ناظران مقدار جدیدی محاسبه نمی‌کنند، فقط به تغییر واکنش نشان می‌دهند. طبق مستندات Apple، The Swift Programming Language (2026)، ناظران برای اعتبارسنجی داده‌ها، همگام‌سازی رابط و ثبت تغییرات در کد ضروری هستند.

نکات اصلی

  • willSet — قبل از ذخیره مقدار جدید ویژگی فراخوانی می‌شود
  • didSet — پس از ذخیره مقدار جدید فراخوانی می‌شود
  • newValue — پارامتر ضمنی در willSet، شامل مقدار جدید
  • oldValue — پارامتر ضمنی در didSet، شامل مقدار قدیمی
  • ناظران — هنگام مقداردهی اولیه و داخل init کار نمی‌کنند

willSet و didSet در Swift چیست؟

willSet و didSet property observers (ناظران ویژگی) در Swift هستند، یک مکانیزم داخلی برای ردیابی تغییرات stored properties.

برخلاف زبان‌های دیگر که نیاز به پیاده‌سازی دستی setters یا سیستم‌های callback دارند، Swift یک syntax اعلانی برای واکنش به تغییرات ارائه می‌دهد. ناظران مستقیماً پس از اعلان ویژگی اضافه می‌شوند و نیازی به فراخوانی جداگانه ندارند.

طبق Apple Developer Documentation (2026)، property observers برای stored properties هر کلاس، ساختار یا شمارش پشتیبانی می‌شوند. آنها با computed properties کار نمی‌کنند، زیرا آنها مقداری را ذخیره نمی‌کنند — برای آنها واکنش به تغییر مستقیماً در setter پیاده‌سازی می‌شود.

چه زمانی willSet فراخوانی می‌شود

willSet بلافاصله قبل از تخصیص مقدار جدید به ویژگی فراخوانی می‌شود. در داخل willSet پارامتر ضمنی newValue در دسترس است که مقدار تعیین‌شده را شامل می‌شود. در این لحظه مقدار فعلی ویژگی هنوز تغییر نکرده است — می‌توانید مقدار قدیمی را مستقیماً از طریق ویژگی بخوانید.

طبق Swift Evolution proposal SE-0001 (2024)، willSet امکان انجام اعتبارسنجی یا ثبت رویداد قبل از تغییر واقعی را فراهم می‌کند. اگر در willSet یک استثنا پرتاب شود — مقدار جدید اعمال نخواهد شد، که ناظران را به یک مکانیزم حفاظت از داده تبدیل می‌کند.

چه زمانی didSet فراخوانی می‌شود

didSet بلافاصله پس از تخصیص مقدار جدید فراخوانی می‌شود. در داخل didSet پارامتر ضمنی oldValue در دسترس است که مقدار قبل از تغییر را شامل می‌شود. در این لحظه ویژگی قبلاً مقدار جدید را دارد و می‌توانید آن را با مقدار قدیمی مقایسه کنید.

طبق Swift by Sundell (2025)، didSet محبوب‌ترین ناظر است، زیرا اغلب برای پردازش پس از تغییر مورد نیاز است: به‌روزرسانی UI، محاسبه مجدد فیلدهای وابسته یا ارسال داده به سرور پس از تغییر.

Syntax ناظران ویژگی

Property observers بلافاصله پس از ویژگی با استفاده از آکولاد اعلان می‌شوند. حداقل syntax فقط به یک ناظر نیاز دارد، اما می‌توان هر دو را اعلان کرد.

swift
var score: Int = 0 {
    willSet {
        print("امتیاز به \(newValue) تغییر خواهد کرد")
    }
    didSet {
        print("امتیاز از \(oldValue) به \(score) تغییر کرد")
    }
}

هر دو ناظر اختیاری هستند — می‌توان فقط willSet یا فقط didSet را مشخص کرد. برای willSet می‌توان نام newValue را با مشخص کردن نام در پرانتز تغییر داد.

swift
var username: String = "guest" {
    willSet(newName) {
        print("در حال تنظیم \(newName)")
    }
    didSet(oldName) {
        print("\(oldName) بود، اکنون \(username)")
    }
}

طبق Swift Language Guide (2026)، تغییر نام پارامترها خوانایی کد را بهبود می‌بخشد، به‌ویژه زمانی که ویژگی و ناظران در یک پروژه بزرگ با نام‌های طولانی استفاده می‌شوند.

willSet و didSet چگونه کار می‌کنند

ترتیب اجرا به‌طور دقیق مشخص شده است: ابتدا willSet (مقدار قدیمی در دسترس است)، سپس تخصیص، سپس didSet (مقدار جدید در دسترس است).

swift
class Temperature {
    var celsius: Double = 0.0 {
        willSet {
            print("دما از \(celsius) به \(newValue) تغییر خواهد کرد")
        }
        didSet {
            if celsius > 100.0 {
                print("نقطه جوش تجاوز شد!")
            }
        }
    }
}

محدودیت مهم: ناظران هنگام مقداردهی اولیه ویژگی در فرآیند ایجاد نمونه فراخوانی نمی‌شوند. در داخل init، تخصیص مقدار willSet و didSet را فعال نمی‌کند — این کار از عوارض جانبی ناخواسته در مرحله ساخت جلوگیری می‌کند.

طبق Apple Swift Blog (2025)، این رفتار با بسیاری از زبان‌های دیگر که در آنها setters حتی در سازنده‌ها فراخوانی می‌شوند متفاوت است. Swift امنیت را انتخاب می‌کند: ناظران فقط پس از تکمیل مقداردهی اولیه شیء شروع به کار می‌کنند.

فراخوانی‌های تودرتو و بازگشت

تغییر ویژگی در داخل didSet می‌تواند منجر به فراخوانی مجدد ناظران شود. Swift بازگشت را مسدود نمی‌کند — برنامه‌نویس باید خودش آن را کنترل کند.

swift
var counter: Int = 0 {
    didSet {
        if counter < 5 {
            counter += 1
        }
    }
}

چنین کدی بازگشت کامل با سرریز پشته ایجاد می‌کند، اگر شرط خروج پیش‌بینی نشده باشد. طبق Stack Overflow Swift Community (2025)، این یکی از رایج‌ترین اشتباهات برنامه‌نویسان مبتدی هنگام کار با property observers است.

ناظران برای ویژگی‌های ساختارها

ساختارها از willSet و didSet برای stored properties بدون محدودیت پشتیبانی می‌کنند. مهم است به خاطر داشته باشید که ساختارها value types هستند و تغییر ویژگی در داخل متد جهش‌دهنده نیز ناظران را فعال می‌کند.

swift
struct Point {
    var x: Double = 0.0 {
        didSet {
            print("X به \(x) تغییر کرد")
        }
    }
    var y: Double = 0.0 {
        didSet {
            print("Y به \(y) تغییر کرد")
        }
    }
}

var point = Point()
point.x = 5.0

کاربرد ناظران در پروژه‌های واقعی

ناظران ویژگی در پروژه‌های Swift برای طیف گسترده‌ای از وظایف استفاده می‌شوند: از همگام‌سازی UI تا اعتبارسنجی داده‌ها و ثبت رویداد.

اعتبارسنجی مقادیر

didSet امکان برگرداندن یا تصحیح مقدار نامعتبر را بلافاصله پس از تنظیم آن فراهم می‌کند. این کار جایگزین setters حجیم در Objective-C می‌شود و یکپارچگی داده را در سطح مدل تضمین می‌کند.

swift
var age: Int = 0 {
    didSet {
        if age < 0 || age > 150 {
            age = oldValue
        }
    }
}

همگام‌سازی UI

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

swift
var userName: String = "" {
    didSet {
        nameLabel.text = userName
    }
}

ثبت تغییرات

willSet برای ثبت رویداد به منظور debugging یا حسابرسی مناسب است. می‌توانید زمان و مقدار جدید را قبل از اعمال آن ثبت کنید و اطمینان حاصل کنید که log حاوی داده‌های اصلی برای تحلیل است.

طبق objc.io (2025)، property observers به‌ویژه در معماری‌هایی با جریان داده یک‌طرفه مفید هستند، جایی که هر تغییر ویژگی برای بازتولید بعدی وضعیت ثبت می‌شود.

مقایسه با computed properties

Computed properties مقدار را در لحظه محاسبه می‌کنند و ذخیره‌سازی ندارند، در حالی که willSet و didSet روی stored property با مقدار واقعی کار می‌کنند.

ویژگیProperty ObserversComputed Properties
ذخیره مقداربلهخیر
اجرا کد هنگام تغییربلهخیر
نوع اعلانvarvar (get/set)
پارامترهای دسترسیnewValue, oldValuenewValue (در set)
مقداردهی اولیهنیاز به مقدار اولیه داردنیاز ندارد

تفاوت کلیدی: computed property در هر بار دسترسی مقدار را محاسبه می‌کند، در حالی که property observer به تغییر مقدار موجود واکنش نشان می‌دهد. انتخاب بین آنها توسط semantics تعیین می‌شود — اگر ویژگی مشتق از داده‌های دیگر است، از computed استفاده کنید؛ اگر این یک مقدار مستقل است که تغییرات آن باید مشاهده شود، از willSet/didSet استفاده کنید.

اشتباهات رایج در استفاده

رایج‌ترین اشتباه — فراخوانی بازگشتی didSet بدون شرط خروج. هر تغییر ویژگی در داخل didSet observer را دوباره فعال می‌کند که منجر به حلقه بی‌نهایت می‌شود.

دومین اشتباه رایج — تلاش برای استفاده از ناظران روی ویژگی‌های let. کامپایلر Swift خطا می‌دهد، زیرا let ثابت است.

سومین اشتباه — نادیده گرفتن این واقعیت که observer هنگام مقداردهی اولیه فراخوانی نمی‌شود. توسعه‌دهندگانی که انتظار فعال شدن willSet در داخل init را دارند با رفتار غیرمنتظره مواجه می‌شوند.

چهارمین مشکل — اعمال ناظران به ویژگی‌ها در extension. Swift افزودن willSet/didSet به stored properties در extension را ممنوع می‌کند.

طبق Ray Wenderlich (2025)، درک این محدودیت‌ها به جلوگیری از اشکالات در مراحل اولیه کمک می‌کند و کد Swift را قابل‌پیش‌بینی‌تر می‌کند.

سوالات متداول

آیا می‌توان از willSet بدون didSet استفاده کرد؟

بله، هر ناظر اختیاری است. می‌توانید فقط willSet، فقط didSet یا هر دو را اعلان کنید.

آیا ناظران در extension کار می‌کنند؟

خیر، Swift افزودن willSet و didSet در extension برای stored properties را ممنوع می‌کند. ناظران فقط در تعریف اصلی نوع اعلان می‌شوند.

آیا ناظران هنگام تغییر ویژگی در داخل init فراخوانی می‌شوند؟

خیر، هنگام مقداردهی اولیه ناظران فراخوانی نمی‌شوند. این یک مکانیزم محافظتی است که از عوارض جانبی در مرحله ساخت شی جلوگیری می‌کند.

willSet چه تفاوتی با setter در computed property دارد؟

willSet یک ناظر stored property است که قبل از تغییر مقدار اجرا می‌شود. Setter در computed property روشی برای محاسبه مقدار جدید است، نه مشاهده مقدار موجود.

چه اتفاقی می‌افتد اگر ویژگی در داخل didSet تغییر کند؟

فراخوانی مجدد didSet باعث بازگشت می‌شود. بدون شرط خروج، این منجر به سرریز پشته و خاتمه اضطراری برنامه می‌شود.

خلاصه

  • willSet — ناظری که قبل از تغییر ویژگی اجرا می‌شود، با دسترسی به newValue
  • didSet — ناظری که پس از تغییر ویژگی اجرا می‌شود، با دسترسی به oldValue
  • Syntax — observers در آکولاد پس از اعلان ویژگی اعلان می‌شوند
  • مقداردهی اولیه — observers در داخل init و هنگام تنظیم مقدار پیش‌فرض کار نمی‌کنند
  • کاربرد — اعتبارسنجی، همگام‌سازی UI، ثبت رویداد، حسابرسی تغییرات
  • بازگشت — تغییر ویژگی در داخل didSet نیاز به شرط خروج صریح دارد
  • Computed — با computed properties اشتباه نگیرید: observers مشاهده می‌کنند، computed محاسبه می‌کنند

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

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

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

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