@State یک Property Wrapper در SwiftUI برای مدیریت وضعیت محلی در داخل یک نمایش است. SwiftUI به طور خودکار نمایش را با هر تغییر در ویژگی @State دوباره ترسیم میکند و رابط را بدون فراخوانی دستی بهروزرسانی واکنشگرا میکند. به گفته Apple Developer Documentation (2025)، @State برای انواع ساده و ساختارهای متعلق به یک نمایش توصیه میشود. @State سادهترین راه برای افزودن تعامل به رابط SwiftUI است.
نکات کلیدی
@State یک Property Wrapper تعبیهشده در SwiftUI است که به نمایش اجازه میدهد وضعیت خود را ذخیره و跟踪 کند. وقتی مقدار @State تغییر میکند، SwiftUI به طور خودکار نمایش را دوباره ترسیم میکند و ویژگی body را دوباره فراخوانی میکند. این اساس برنامهنویسی واکنشگرا در SwiftUI است: توسعهدهنده وضعیت را اعلام میکند و فریمورک همگامسازی رابط را بر عهده میگیرد.
@State یک ناحیه ذخیرهسازی در heap ایجاد میکند که توسط SwiftUI مدیریت میشود. این ناحیه ماندگار است — از مقداردهی اولیه مکرر ساختار نمایش که در هر رندر رخ میدهد، جان سالم به در میبرد. SwiftUI از شناسه نمایش (تولیدشده بر اساس موقعیت در سلسلهمراتب) برای اتصال ویژگی @State به یک نمایش خاص استفاده میکند. به این ترتیب، وضعیت هنگام بهروزرسانی نمایش والد بازنشانی نمیشود.
محدودیت مهم: @State فقط برای انواع مقدار (ساختارها، شمارشها، انواع ابتدایی) طراحی شده است. برای انواع ارجاعی (کلاسها) از @StateObject یا @ObservedObject استفاده کنید. اگر یک کلاس را به ویژگی @State اختصاص دهید، SwiftUI نمیتواند تغییرات داخل شیء را تشخیص دهد — فقط جایگزینی کامل مرجع را.
SwiftUI @State را از طریق مکانیزم داخلی Storage پیادهسازی میکند. هر ویژگی @State یک سلول حافظه اختصاصی دریافت میکند که در کانتینر ذخیرهسازی مخصوص نمایش نگهداری میشود. هنگامی که نوشتن در wrappedValue انجام میشود، SwiftUI از طریق didSet گراف وابستگی خود (dependency graph) را از نیاز به ترسیم مجدد مطلع میکند.
struct ContentView: View {
@State private var name: String = "User"
@State private var isLoggedIn: Bool = false
var body: some View {
VStack {
Text("سلام، \(name)")
Button(isLoggedIn ? "خروج" : "ورود") {
isLoggedIn.toggle()
}
}
}
}
در مثال دو ویژگی @State وجود دارد: name (String) و isLoggedIn (Bool). هنگام فراخوانی isLoggedIn.toggle()، SwiftUI ContentView را به عنوان نیازمند بهروزرسانی علامتگذاری میکند و body را در چرخه رندر بعدی دوباره اجرا میکند. نکته کلیدی: ویژگیهای @State همیشه با اصلاحکننده private اعلام میشوند — این نشانه آن است که وضعیت منحصراً به نمایش فعلی تعلق دارد و نباید از خارج مستقیماً تغییر کند.
برای مشاهده تغییرات، SwiftUI از CurrentValueSubject از Combine استفاده میکند. هر ویژگی @State یک ناشر پنهان ایجاد میکند که سیستم را در هر تغییر مطلع میکند. این به SwiftUI اجازه میدهد فقط حداقل مجموعه لازم از نمایشها را دوباره ترسیم کند و از بهروزرسانی کامل سلسلهمراتب جلوگیری کند.
@State برای وضعیتهای محلی ساده بهینه است: فیلدهای متنی جستجو، پرچمهای بولی برای پنجرههای مودال، کلیدهای تنظیمات، شمارندهها، عناصر لیست انتخابشده. اگر مقدار فقط در یک نمایش و کامپوننتهای تو در توی آن (از طریق @Binding) استفاده میشود، @State انتخاب درستی است. برای وضعیتهایی که باید پس از بسته شدن نمایش باقی بمانند (مانند دادههای فرم)، @State نیز مناسب است تا زمانی که نمایش در سلسلهمراتب باقی بماند.
از @State برای وضعیتهای سراسری برنامه، ذخیره دادههای شبکه یا اشیائی که در چندین صفحه استفاده میشوند، استفاده نکنید. برای این اهداف از @StateObject و @EnvironmentObject استفاده میشود. همچنین @State برای ذخیره حجم زیادی از دادهها مناسب نیست — هر بار که تغییر کند، کل نمایش دوباره ترسیم میشود.
@Binding پلی بین @State در نمایش والد و نمایش فرزندی است که نیاز به تغییر این وضعیت دارد. والد @State را اعلام میکند و کامپوننت فرزند Binding را از طریق پروجکشن $ دریافت میکند. تغییر Binding در نمایش فرزند به طور خودکار @State را در والد بهروزرسانی میکند — و بالعکس. این جریان یکطرفه داده را با امکان بازخورد فراهم میکند.
struct ParentView: View {
@State private var text: String = ""
var body: some View {
ChildView(text: $text)
}
}
struct ChildView: View {
@Binding var text: String
var body: some View {
TextField("Enter text", text: $text)
}
}
در لیستینگ، ParentView مالک @State text است و ChildView $text را به عنوان Binding دریافت میکند. TextField داخل ChildView از طریق text: $text به این Binding متصل میشود. وقتی کاربر در TextField تایپ میکند، مقدار در ChildView از طریق Binding تغییر میکند که باعث بهروزرسانی @State در ParentView میشود. هر دو نمایش با مقدار جدید دوباره ترسیم میشوند.
رایجترین اشتباه — اختصاص کلاس به ویژگی @State. اگر @State var model = MyClass() بنویسید، SwiftUI نمیتواند تغییرات ویژگیهای داخل کلاس را ردیابی کند — فقط جایگزینی خود شیء. برای کلاسها همیشه از @StateObject استفاده کنید. دومین مشکل رایج — اعلام @State بدون اصلاحکننده private که اصل کپسولهسازی وضعیت را نقض میکند.
ارسال مستقیم @State به نمایش فرزند بدون $ — یکی دیگر از اشتباهات رایج. اگر به جای TextField(text: $text) از TextField(text: text) استفاده کنید، کامپوننت فرزند یک رشته ساده دریافت میکند نه Binding. تغییر متن در TextField با @State والد همگامسازی نخواهد شد. همیشه از پروجکشن $ برای ارسال Binding استفاده کنید.
سومین اشتباه — ویژگیهای @State متعدد برای دادههای مرتبط. اگر چند مقدار منطقاً یک کل واحد را تشکیل میدهند (مثلاً فیلدهای فرم)، آنها را در یک ساختار با یک @State واحد ترکیب کنید. این کار ارسال وضعیت به نمایشهای فرزند را سادهتر میکند و تعداد محرکهای بهروزرسانی جداگانه را کاهش میدهد.
@State در بیشتر پروژههای SwiftUI برای تعامل اولیه استفاده میشود. بیایید مثال فرم ورود را بررسی کنیم، جایی که @State فیلدهای متنی و وضعیت بارگذاری را مدیریت میکند. این الگو در هر برنامهای — از یادداشتهای ساده تا راهحلهای پیچیده شرکتی — یافت میشود.
struct LoginView: View {
@State private var email: String = ""
@State private var password: String = ""
@State private var isLoading: Bool = false
@State private var errorMessage: String?
var body: some View {
Form {
TextField("Email", text: $email)
SecureField("Password", text: $password)
Button("ورود") {
login()
}.disabled(isLoading)
}
}
private func login() {
isLoading = true
// انجام درخواست شبکه
}
}
در مثال چهار ویژگی @State وجود دارد: email و password برای فیلدهای فرم، isLoading برای نشان دادن بارگذاری و errorMessage برای نمایش خطاها. هر ویژگی به طور مستقل بخش خود از رابط را مدیریت میکند. هنگام تغییر isLoading، دکمه به طور خودکار از طریق disabled(isLoading) قفل میشود — بدون بهروزرسانی دستی UI.
سؤالات متداول
@State برای وضعیت محلی یک نمایش خاص طراحی شده است. اصلاحکننده private تضمین میکند که سایر کامپوننتها نمیتوانند مستقیماً آن را تغییر دهند و کپسولهسازی را نقض کنند. برای دسترسی خارجی از پروجکشن $ استفاده کنید.
بله، @State از آرایهها و دیکشنریها پشتیبانی میکند زیرا اینها انواع مقدار هستند. با این حال، هنگام تغییر یک عنصر آرایه، SwiftUI کل نمایش را دوباره ترسیم میکند. برای لیستهای بزرگ، استفاده از @StateObject با @Published مؤثرتر است.
@State به درستی با انواع Optional کار میکند. هنگام اختصاص nil، SwiftUI تغییر را تشخیص میدهد و نمایش را دوباره ترسیم میکند. این برای وضعیتهایی مانند errorMessage: String? مفید است، جایی که nil به معنای عدم وجود خطا است.
@State مقدار را تا زمانی که نمایش در سلسلهمراتب باقی بماند حفظ میکند. اگر نمایش از سلسلهمراتب حذف و دوباره اضافه شود، @State با مقدار پیشفرض دوباره مقداردهی میشود. برای ماندگاری از @AppStorage استفاده کنید.
بله، تغییر را در withAnimation قرار دهید: withAnimation(.easeInOut) { isExpanded.toggle() }. SwiftUI انتقال بین وضعیت قدیم و جدید رابط را با نوع انیمیشن مشخصشده انیمیشن میکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید