@State هو Property Wrapper في SwiftUI لإدارة الحالة المحلية داخل عرض واحد. يعيد SwiftUI رسم العرض تلقائياً كلما تغيرت خاصية @State، مما يجعل الواجهة تفاعلية دون استدعاءات تحديث يدوية. وفقاً لوثائق Apple Developer (2025)، يُوصى باستخدام @State للأنواع والهياكل البسيطة التي تنتمي إلى عرض واحد. @State هو أبسط طريقة لإضافة التفاعلية إلى واجهة SwiftUI.
الخلاصة
@State هو Property Wrapper مدمج في SwiftUI يسمح للعرض بتخزين وتتبع حالته الخاصة. عندما تتغير قيمة @State، يعيد SwiftUI رسم العرض تلقائياً عن طريق استدعاء خاصية body مرة أخرى. هذا هو أساس البرمجة التفاعلية في SwiftUI: يعلن المطور عن الحالة، ويتولى الإطار مزامنة الواجهة.
ينشئ @State منطقة تخزين في الكومة تُدار بواسطة SwiftUI. هذه المنطقة ثابتة — تبقى بعد عمليات التهيئة المتكررة لهيكل العرض التي تحدث في كل عرض. يستخدم SwiftUI معرف العرض (المُولد بناءً على موقعه في التسلسل الهرمي) لربط خاصية @State بعرض معين. بفضل هذا، لا يتم إعادة تعيين الحالة عند تحديث العرض الأب.
قيود مهمة: @State مخصص فقط لـ أنواع القيمة (الهياكل، التعدادات، الأنواع البدائية). للأنواع المرجعية (الفئات)، استخدم @StateObject أو @ObservedObject. إذا أسندت فئة إلى خاصية @State، لن يتمكن SwiftUI من اكتشاف التغييرات داخل الكائن — فقط استبدال المرجع بالكامل.
ينفذ SwiftUI @State من خلال آلية التخزين الداخلية. تحصل كل خاصية @State على خلية ذاكرة مخصصة مخزنة في حاوية تخزين خاصة بالعرض. عندما يحدث كتابة إلى wrappedValue، يُعلم SwiftUI رسم التبعيات الخاص به عبر didSet بضرورة إعادة الرسم.
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 بهذا Binding عبر text: $text. عندما يكتب المستخدم في 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) — دون تحديث يدوي للواجهة.
الأسئلة الشائعة
@State مصمم للحالة المحلية لعرض معين. المُعدِّل private يضمن أن المكونات الأخرى لا يمكنها تغييره مباشرة، مما يكسر التغليف. للوصول الخارجي، استخدم إسقاط $.
نعم، @State يدعم المصفوفات والقواميس لأنها أنواع قيمة. ومع ذلك، عندما يتغير عنصر في مصفوفة، يعيد SwiftUI رسم العرض بأكمله. للقوائم الكبيرة، @StateObject مع @Published أكثر كفاءة.
@State يعمل بشكل صحيح مع الأنواع الاختيارية. عند تعيين nil، يكتشف SwiftUI التغيير ويعيد رسم العرض. هذا مناسب لحالات مثل errorMessage: String؟، حيث nil يعني عدم وجود خطأ.
@State يحتفظ بالقيمة طالما بقي العرض في التسلسل الهرمي. إذا تمت إزالة العرض من التسلسل الهرمي وإضافته مرة أخرى، يُعاد تهيئة @State بالقيمة الافتراضية. للاستمرارية، استخدم @AppStorage.
نعم، لف التغيير في withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. يقوم SwiftUI بتحريك الانتقال بين الحالة القديمة والجديدة للواجهة مع نوع الحركة المحدد.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا