@Published — یک property wrapper از چارچوب Combine است که به طور خودکار تغییرات ویژگی کلاس مطابق با پروتکل ObservableObject را منتشر میکند. وقتی مقدار ویژگی مشخصشده با @Published تغییر میکند، SwiftUI از طریق objectWillChange سیگنال دریافت کرده و همه نمایهایی که به آن شیء مشترک شدهاند را دوباره رسم میکند. به استناد مستندات Apple Combine Framework Documentation (2025)، @Published یک Publisher تولید میکند که میتوان آن را از طریق اپراتورهای Combine: map، filter، debounce و سایر آنها تحویل داد. این @Published را به پلی کلیدی بین دادهها و رابط کاربر در معماری MVVM تبدیل میکند.
نکات کلیدی
objectWillChange فراخوانده میشود که باعث ترسیم دوباره نمایهای مشترک میشود$property در دسترس است — میتوان مشترک شد، ترکیب و تحویل داد@Published — یک property wrapper است که در ماژول Combine تعریف شده و به ویژگی کلاس این قابلیت را میدهد که به طور خودکار مشترکان را از تغییرات آگاه کند. آن فقط داخل کلاس (نه در ساختار) و فقط به ویژگیهای کلاس مطابق با پروتکل ObservableObject قابل اعمال است.
وقتی مقدار ویژگی @Published تغییر میکند، Combine از طریق پابلیشر داخلی یک رویداد تولید میکند که از طریق پیشوند دلار قابل دسترسی است: $propertyName. این پابلیشر — ObservableObjectPublisher است که متعلق به خود ObservableObject است. SwiftUI به طور خودکار به آن مشترک میشود وقتی نما از @ObservedObject یا @StateObject استفاده میکند، و نما را با هر تغییر در هر ویژگی @Published داخل شیء دوباره رسم میکند.
به استناد کتاب مت نیوبورگ «IOS 18 Programming Fundamentals with Swift» (2025)، @Published یک پیچیده سازی مناسب از الگوی willSet است که به طور خودکار objectWillChange.send() را فراخوان میکند. در واقع کامپایلر @Published را به یک ویژگی محاسبهشده با ناظر willSet تبدیل میکند که در مقایسه با پیادهسازی دستی، سرراشت صفر رونتایم دارد.
از @Published برای همه ویژگیهای ObservableObject که تغییرات آنها باید در رابط منعکس شود استفاده کنید. برای ویژگیهایی که بر UI تأثیر نمیگذارند، stored properties عادی بدون @Published تعداد ترسیمهای ضروری را کاهش میدهند.
@Published در زمان کامپیلاسیون دو عنصر کلیدی تولید میکند. اولی — یک ویژگی ذخیرهشده با ناظر willSet که قبل از نوشتن مقدار جدید، objectWillChange.send() را فراخوان میکند. دومی — پروژکشن $propertyName که Published.Publisher را بازمیگرداند که میتوان مستقیماً در پایپلاینهای Combine استفاده کرد.
کلاس Settings را با سه ویژگی در نظر بگیرید: دو تا @Published و یکی عادی:
class Settings: ObservableObject {
@Published var username: String = "Guest"
@Published var isDarkMode = false
var lastLogin: Date = Date() // بدون @Published
}
با تغییر username یا isDarkMode، SwiftUI همه نمایهایی که به نمونه Settings مشترک شدهاند را دوباره رسم میکند. تغییر lastLogin باعث ترسیم دوباره نمیشود. اگر بنیاز است مشترکان را در مورد تغییر ویژگی عادی مطلع کنید، میتوانید objectWillChange.send() را در ناظر willSet فراخوان کنید.
یک جزئیات مهم: @Published تغییرات را فقط در زمان نوشتن مستقیم در ویژگی منتشر میکند. اگر ویژگی از نوع ارجاعی (کلاس) باشد و وضعیت داخلی آن بدون جایگزینی ارجاع تغییر کند، @Published آن را تشخیص نمیدهد. در چنین مواردی ارسال دستی رویداد یا جایگزینی با نوع مقدار (ساختار) مورد نیاز است.
@Published به طور گسترده با Combine یکپارچه شده است — هر ویژگی @Published به طور خودکار یک پابلیشر از طریق پروژکشن $propertyName ارائه میدهد. این امکان استفاده از اپراتورهای Combine برای پالایش، تحویل، ترکیب و پردازش تأخیری مقادیر را فراهم میکند.
سناریو معمولی — جستجو با debounce. فیلد ورودی به ویژگی @Published به نام searchText متصل شده است، اما درخواست به سرور تنها بعد از مکث 300 میلیثانیه ارسال شود. Combine با $searchText.debounce این را در یک خط حل میکند:
class SearchViewModel: ObservableObject {
@Published var searchText = ""
@Published var results: [String] = []
private var cancellables = Set<AnyCancellable>()
init() {
setupSearchSubscription()
}
private func setupSearchSubscription() {
$searchText
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.sink { [weak self] text in
self?.performSearch(text)
}
.store(in: &cancellables)
}
private func performSearch(_ text: String) { }
}
به استناد مقاله جان ساندلز (Swift by Sundell, 2024)، ترکیب @Published با Combine الگوی استاندارد برای پایپلاینهای واکنشی در برنامههای SwiftUI است: validation، debounce، throttle، combineLatest، merge با سایر publishers. @Published به عنوان پلی بین کد UI امری و Combine واکنشی عمل میکند.
با عرضه iOS 17، Apple ماکروی @Observable را معرفی کرد که رویکرد جایگزینی به واکنشپذیری بدون ObservableObject و @Published ارائه میدهد. @Observable به طور خودکار دسترسی به ویژگیها را در سطح خواندن ردیابی میکند، نه نوشتن، که ترسیمهای دقیقتری را به این معنی ایجاد میکند — تنها نمایی که ویژگی تغییریافته مشخصی را میخواند بهروز میشود.
اما این به معنای کاهنه شدن @Published نیست. @Published هنوز هم وقتی انتگراسیون با پایپلاینهای Combine مورد نیاز است ضروری است — پروژکشن $propertyName پابلیشری را فراهم میکند که در @Observable وجود ندارد. علاوه بر این، برای سازگاری با iOS 16 و پایینتر، @Published+ObservableObject تنها گزینه است. به استناد جلسه Apple WWDC 2023 «Discover Observation in SwiftUI»، Apple @Observable را برای پروژههای جدید توصیه میکند، اما به طور واضح از @Published برای کد موجود و سناریوهای Combine پشتیبانی میکند.
در عمل، بسیاری از پروژهها از رویکرد ترکیبی استفاده میکنند: مدلهای داده جدید با @Observable نوشته میشوند، و ObservableObject موجود با @Published بدون بازنویسی باقی میمانند. @Published همچنین وقتی نیاز به کنترل دقیق بر انتشار است ضروری است — مثلاً، به تأخیر انداختن اعلان تا پایان بهروزرسانی تشکیلاتی چند ویژگی.
اشتباه اول — استفاده از @Published در ساختار. کامپایلر خطای زیر را نمایش میدهد: «Property wrapper cannot be applied to a computed property» یا «'@Published' is only available on members of a class». @Published نیازمند سمانتیک ارجاعی است، زیرا ObservableObjectPublisher کلاسی است که باید برای هر نمونه منحصر به فرد باشد.
اشتباه دوم — تغییر محتوای ویژگی ارجاعی بدون جایگزینی ارجاع. اگر ویژگی @Published از نوع ماسیو [String] باشد و شما array.append("new") را فراخوان کنید، @Published تغییر را تشخیص نمیدهد، زیرا ارجاع به ماسیو تغییر نکرده است. راه حل: مقدار جدیدی به ویژگی تخصیص دهید array = array + ["new"] یا از objectWillChange.send() به صورت دستی استفاده کنید.
اشتباه سوم — تعداد زیاد ویژگیهای @Published. هر ویژگی @Published باعث ترسیم دوباره همه نمایهای مشترک به ObservableObject میشود، نه تنها آنهایی که این ویژگی را میخوانند. به استناد Point-Free (2025)، تقسیم یک ObservableObject بزرگ به چند ObservableObject کوچک با @StateObject و @EnvironmentObject تعداد ترسیمهای ضروری را کاهش داده و عملکرد را بهبود میبخشد.
نمونه اول — ViewModel فرم ثبت نام با اعتبارسنجی. ویژگیهای @Published email و password نمایش خطاهای اعتبارسنجی را از طریق pipeline Combine فعال میکنند:
class RegistrationViewModel: ObservableObject {
@Published var email = ""
@Published var password = ""
@Published var emailError: String?
@Published var isFormValid = false
private var cancellables = Set<AnyCancellable>()
init() {
$email
.map { $0.contains("@") ? nil : "Invalid email" }
.assign(to: &$emailError)
.store(in: &cancellables)
$email.combineLatest($password)
.map { !$0.isEmpty && !$1.isEmpty }
.assign(to: &$isFormValid)
.store(in: &cancellables)
}
}
نمونه دوم — انتشار دستی برای کولکسیون از عناصر ارجاعی. به جای جایگزینی کل ماسیو با هر تغییر داخل عنصر، از objectWillChange.send() استفاده میشود:
class TodoItem {
var title: String
var isDone = false
init(title: String) { self.title = title }
}
class TodoListViewModel: ObservableObject {
@Published var items: [TodoItem] = []
func toggle(item: TodoItem) {
item.isDone.toggle()
self.objectWillChange.send() // اعلان دستی
}
}
نمونه سوم — Assign به ویژگی @Published از طریق Combine. با استفاده از نحوه جدید Swift 5.9، میتوان مستقیماً از طریق پروژکشن assign(to: &$property) بدون پیچیده سازی Optional تخصیص داد. این کوتاهترین راه برای اتصال پابلیشر به ویژگی @Published بدون ایجاد اشتراک است.
سوالات متداول
خیر، @Published فقط داخل کلاس مطابق با ObservableObject قابل اعمال است. در ساختارها از @State برای وضعیت محلی یا @Bindable با ماکروی @Observable در iOS 17+ استفاده کنید. تلاش برای اعمال @Published در ساختار باعث خطای کامپیلاسیون میشود.
به طور صحیح: مقدار جدید را تماماً تخصیص دهید (array = array + ["new"]). @Published جایگزینی ارجاع را ردیابی میکند، نه تغییر محتوا. برای کولکسیونهای از نوع ارجاعی، پس از تغییر وضعیت داخلی عناصر، از objectWillChange.send() به صورت دستی استفاده کنید.
@State برای وضعیت محلی داخل یک نما طراحی شده و فقط با انواع مقدار کار میکند. @Published — برای ویژگیهای ObservableObject است که میتوانند توسط چندین نما از طریق @ObservedObject یا @EnvironmentObject خوانده شوند. @State سادهتر است، @Published به دلیل یکپارچگی با Combine قدرتمندتر است.
تنها برای آنهایی که تغییراتشان باید UI را بهروز کند. ویژگیهای برای محاسبات داخلی، کش یا علمتهای موقت نیازی به @Published ندارند — این تعداد ترسیمهای ضروری را کاهش میدهد. از @Published به عنوان سیگنالی برای این که «این ویژگی برای رابط مهم است» استفاده کنید.
SwiftUI با Core Data از طریق @FetchRequest و @ObservedObject برای NSManagedObject یکپارچه میشود. ManagedObject در حال حاضر مطابق با ObservableObject است، بنابراین @Published لازم نیست — NSManagedObject خود در مورد تغییرات اعلان میدهد. @Published در لایه ViewModel بین Core Data و UI برای تبدیل دادهها استفاده میشود.
نتایج
objectWillChange.send() را فراخوان میکند، و از طریق پروژکشن $property پابلیشر تولید میکندassign(to: &$property) در Swift 5.9 امکان اشتراک مستقیم پابلیشر به ویژگی @Published را فراهم میکندما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.