@State — چیست، هدف و کاربرد در SwiftUI

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

@State یک Property Wrapper در SwiftUI برای مدیریت وضعیت محلی در داخل یک نمایش است. SwiftUI به طور خودکار نمایش را با هر تغییر در ویژگی @State دوباره ترسیم می‌کند و رابط را بدون فراخوانی دستی به‌روزرسانی واکنش‌گرا می‌کند. به گفته Apple Developer Documentation (2025)، @State برای انواع ساده و ساختارهای متعلق به یک نمایش توصیه می‌شود. @State ساده‌ترین راه برای افزودن تعامل به رابط SwiftUI است.

نکات کلیدی

  • @State — Property Wrapper برای وضعیت محلی متعلق به یک نمایش
  • به‌روزرسانی خودکار — SwiftUI با تغییر ویژگی @State بدنه را دوباره اجرا می‌کند
  • انواع ساده — @State برای String، Int، Bool، enum و ساختارها مناسب است
  • به نمایش‌های تو در تو ارسال نکنید — برای تغییر از کامپوننت‌های فرزند از @Binding استفاده کنید
  • private — ویژگی‌های @State همیشه با اصلاح‌کننده private اعلام می‌شوند

@State در SwiftUI چیست؟

@State یک Property Wrapper تعبیه‌شده در SwiftUI است که به نمایش اجازه می‌دهد وضعیت خود را ذخیره و跟踪 کند. وقتی مقدار @State تغییر می‌کند، SwiftUI به طور خودکار نمایش را دوباره ترسیم می‌کند و ویژگی body را دوباره فراخوانی می‌کند. این اساس برنامه‌نویسی واکنش‌گرا در SwiftUI است: توسعه‌دهنده وضعیت را اعلام می‌کند و فریمورک همگام‌سازی رابط را بر عهده می‌گیرد.

@State یک ناحیه ذخیره‌سازی در heap ایجاد می‌کند که توسط SwiftUI مدیریت می‌شود. این ناحیه ماندگار است — از مقداردهی اولیه مکرر ساختار نمایش که در هر رندر رخ می‌دهد، جان سالم به در می‌برد. SwiftUI از شناسه نمایش (تولیدشده بر اساس موقعیت در سلسله‌مراتب) برای اتصال ویژگی @State به یک نمایش خاص استفاده می‌کند. به این ترتیب، وضعیت هنگام به‌روزرسانی نمایش والد بازنشانی نمی‌شود.

محدودیت مهم: @State فقط برای انواع مقدار (ساختارها، شمارش‌ها، انواع ابتدایی) طراحی شده است. برای انواع ارجاعی (کلاس‌ها) از @StateObject یا @ObservedObject استفاده کنید. اگر یک کلاس را به ویژگی @State اختصاص دهید، SwiftUI نمی‌تواند تغییرات داخل شیء را تشخیص دهد — فقط جایگزینی کامل مرجع را.

@State در پشت صحنه چگونه کار می‌کند؟

SwiftUI @State را از طریق مکانیزم داخلی Storage پیاده‌سازی می‌کند. هر ویژگی @State یک سلول حافظه اختصاصی دریافت می‌کند که در کانتینر ذخیره‌سازی مخصوص نمایش نگهداری می‌شود. هنگامی که نوشتن در wrappedValue انجام می‌شود، SwiftUI از طریق didSet گراف وابستگی خود (dependency graph) را از نیاز به ترسیم مجدد مطلع می‌کند.

swift
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 در پروژه استفاده کنیم

@State برای وضعیت‌های محلی ساده بهینه است: فیلدهای متنی جستجو، پرچم‌های بولی برای پنجره‌های مودال، کلیدهای تنظیمات، شمارنده‌ها، عناصر لیست انتخاب‌شده. اگر مقدار فقط در یک نمایش و کامپوننت‌های تو در توی آن (از طریق @Binding) استفاده می‌شود، @State انتخاب درستی است. برای وضعیت‌هایی که باید پس از بسته شدن نمایش باقی بمانند (مانند داده‌های فرم)، @State نیز مناسب است تا زمانی که نمایش در سلسله‌مراتب باقی بماند.

  • فیلدهای متنی — @State برای ذخیره متن واردشده در TextField
  • پرچم‌های بولی — @State برای نمایش/پنهان‌کردن پنجره‌های مودال و sheet
  • انتخاب عناصر — @State برای پیگیری تب یا ردیف انتخاب‌شده
  • شمارنده‌ها — @State برای مقادیر عددی با افزایش/کاهش
  • محاسبات میانی — @State برای ذخیره نتایج در داخل نمایش

از @State برای وضعیت‌های سراسری برنامه، ذخیره داده‌های شبکه یا اشیائی که در چندین صفحه استفاده می‌شوند، استفاده نکنید. برای این اهداف از @StateObject و @EnvironmentObject استفاده می‌شود. همچنین @State برای ذخیره حجم زیادی از داده‌ها مناسب نیست — هر بار که تغییر کند، کل نمایش دوباره ترسیم می‌شود.

@State و @Binding: کار مشترک

@Binding پلی بین @State در نمایش والد و نمایش فرزندی است که نیاز به تغییر این وضعیت دارد. والد @State را اعلام می‌کند و کامپوننت فرزند Binding را از طریق پروجکشن $ دریافت می‌کند. تغییر Binding در نمایش فرزند به طور خودکار @State را در والد به‌روزرسانی می‌کند — و بالعکس. این جریان یک‌طرفه داده را با امکان بازخورد فراهم می‌کند.

swift
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. اگر @State var model = MyClass() بنویسید، SwiftUI نمی‌تواند تغییرات ویژگی‌های داخل کلاس را ردیابی کند — فقط جایگزینی خود شیء. برای کلاس‌ها همیشه از @StateObject استفاده کنید. دومین مشکل رایج — اعلام @State بدون اصلاح‌کننده private که اصل کپسوله‌سازی وضعیت را نقض می‌کند.

ارسال مستقیم @State به نمایش فرزند بدون $ — یکی دیگر از اشتباهات رایج. اگر به جای TextField(text: $text) از TextField(text: text) استفاده کنید، کامپوننت فرزند یک رشته ساده دریافت می‌کند نه Binding. تغییر متن در TextField با @State والد همگام‌سازی نخواهد شد. همیشه از پروجکشن $ برای ارسال Binding استفاده کنید.

سومین اشتباه — ویژگی‌های @State متعدد برای داده‌های مرتبط. اگر چند مقدار منطقاً یک کل واحد را تشکیل می‌دهند (مثلاً فیلدهای فرم)، آنها را در یک ساختار با یک @State واحد ترکیب کنید. این کار ارسال وضعیت به نمایش‌های فرزند را ساده‌تر می‌کند و تعداد محرک‌های به‌روزرسانی جداگانه را کاهش می‌دهد.

نمونه‌های استفاده از @State در SwiftUI

@State در بیشتر پروژه‌های SwiftUI برای تعامل اولیه استفاده می‌شود. بیایید مثال فرم ورود را بررسی کنیم، جایی که @State فیلدهای متنی و وضعیت بارگذاری را مدیریت می‌کند. این الگو در هر برنامه‌ای — از یادداشت‌های ساده تا راه‌حل‌های پیچیده شرکتی — یافت می‌شود.

swift
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 برای وضعیت محلی یک نمایش خاص طراحی شده است. اصلاح‌کننده private تضمین می‌کند که سایر کامپوننت‌ها نمی‌توانند مستقیماً آن را تغییر دهند و کپسوله‌سازی را نقض کنند. برای دسترسی خارجی از پروجکشن $ استفاده کنید.

آیا @State می‌تواند آرایه یا دیکشنری داشته باشد؟

بله، @State از آرایه‌ها و دیکشنری‌ها پشتیبانی می‌کند زیرا اینها انواع مقدار هستند. با این حال، هنگام تغییر یک عنصر آرایه، SwiftUI کل نمایش را دوباره ترسیم می‌کند. برای لیست‌های بزرگ، استفاده از @StateObject با @Published مؤثرتر است.

هنگام اختصاص nil به ویژگی @State با نوع Optional چه اتفاقی می‌افتد؟

@State به درستی با انواع Optional کار می‌کند. هنگام اختصاص nil، SwiftUI تغییر را تشخیص می‌دهد و نمایش را دوباره ترسیم می‌کند. این برای وضعیت‌هایی مانند errorMessage: String? مفید است، جایی که nil به معنای عدم وجود خطا است.

@State در هنگام ظهور مجدد نمایش چگونه رفتار می‌کند؟

@State مقدار را تا زمانی که نمایش در سلسله‌مراتب باقی بماند حفظ می‌کند. اگر نمایش از سلسله‌مراتب حذف و دوباره اضافه شود، @State با مقدار پیش‌فرض دوباره مقداردهی می‌شود. برای ماندگاری از @AppStorage استفاده کنید.

آیا می‌توان تغییرات @State را انیمیشن کرد؟

بله، تغییر را در withAnimation قرار دهید: withAnimation(.easeInOut) { isExpanded.toggle() }. SwiftUI انتقال بین وضعیت قدیم و جدید رابط را با نوع انیمیشن مشخص‌شده انیمیشن می‌کند.

خلاصه

  • @State — Property Wrapper برای وضعیت محلی یک نمایش که به طور خودکار رابط را به‌روزرسانی می‌کند
  • مناسب است برای انواع ساده: String، Int، Bool و همچنین ساختارها و enum
  • مناسب نیست برای انواع ارجاعی (کلاس‌ها) — از @StateObject استفاده کنید
  • همیشه private — وضعیت نباید از خارج مستقیماً تغییر کند
  • پروجکشن $ — Binding برای انتقال حق تغییر به نمایش‌های فرزند ایجاد می‌کند
  • چند @State در یک نمایش — روشی عادی برای وضعیت‌های مستقل
  • withAnimation — امکان انیمیشن تغییرات ویژگی‌های @State را فراهم می‌کند

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

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

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

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