SwiftUI: ما هو، المفاهيم الأساسية و View Protocol

المؤلف: IT Sectr نُشر: 2026-04-30 وقت القراءة: 8 دق

SwiftUI هو إطار عمل تصريحي من Apple لبناء واجهات المستخدم عبر جميع منصات النظام البيئي. بدلاً من وصف الخطوات بشكل أمري، يصرّح المطور كيف يجب أن تبدو الواجهة، ويتولى SwiftUI عرضها وتحديثها. وفقاً لـ Apple Developer Documentation (2025)، يدعم SwiftUI iOS 15+ و iPadOS 15+ و macOS 12+ و watchOS 8+ و tvOS 15+ ويستخدم View Protocol ككتلة بناء أساسية لجميع مكونات الواجهة.

الخلاصة

  • SwiftUI هو إطار عمل تصريحي من Apple حيث يصف المطور الواجهة ويتم تنفيذ التحديثات تلقائياً.
  • View Protocol مع الخاصية body هو أساس أي مكون واجهة في SwiftUI، يعيد وصف الشاشة من خلال تركيب العروض.
  • Property Wrappers — @State، @Binding، @ObservedObject، @StateObject — تدير الحالة وتطلق إعادة الرسم عند تغيير البيانات.
  • NavigationStack (iOS 16+) هي واجهة برمجة تنقل حديثة مع مسارات آمنة النوع وتحولات تصريحية.
  • Modifier هو سلسلة استدعاءات لتخصيص مظهر وسلوك العروض دون وراثة الفئات.

ما هو SwiftUI؟

SwiftUI هو إطار عمل تصريحي قدمته Apple في 2019 ليحل محل UIKit في المشاريع الجديدة. بدلاً من إنشاء مثيلات UIView يدوياً وإضافتها إلى التسلسل الهرمي، يصف المطور الواجهة من خلال هياكل تتوافق مع بروتوكول View. يحسب SwiftUI تلقائياً الفرق بين الحالة الحالية والجديدة ويعيد رسم الأجزاء المتغيرة فقط باستخدام محرك العرض الخاص به.

الإطار مكتوب بلغة Swift باستخدام دلالات القيمة (هياكل وليست فئات)، مما يجعل مكونات الواجهة خفيفة الوزن وآمنة للخيوط. على عكس UIKit، حيث يمكن أن يزن UIViewController 200+ بايت بسبب وقت تشغيل Objective-C، فإن SwiftUI View هي مجرد هيكل بحجم بضعة بايتات. هذا مهم بشكل خاص لـ watchOS بذاكرتها المحدودة.

تعدد المنصات في SwiftUI

نفس وصف View يعمل على iPhone و iPad و Mac و Apple Watch و Apple TV و Apple Vision Pro. SwiftUI يكيّف الواجهة مع المنصة: إيماءات اللمس على iOS، اختصارات لوحة المفاتيح على macOS، التمرير بـ Digital Crown على watchOS. هذا يقلل وقت التطوير للشركات التي تطلق تطبيقات على منصات Apple متعددة، لكنه يتطلب تهيئة إضافية للعناصر الخاصة بكل منصة.

View Protocol وجسم العرض

في SwiftUI، كل شاشة هي هيكل يطبق بروتوكول View بمتطلب واحد: خاصية محوسبة body من النوع some View. الكلمة المفتاحية some (نوع غير شفاف) تخفي النوع الملموس للعرض، مما يسمح لـ SwiftUI بتحسين العرض. داخل body، يدمج المطور المكونات الجاهزة — Text، Image، Button، List — باستخدام ViewBuilder، الذي يجمع عدة عروض في واحد.

swift
struct GreetingView: View {
    let name: String

    var var body: some View {
        VStack {
            Text("مرحبا، \(name)!")
                .font(.title)
                .foregroundColor(.blue)
            Image(systemName: "hand.wave")
                .imageScale(.large)
        }
        .padding()
    }
}

في المثال، VStack (المكدس العمودي) يحتوي على Text و Image. قيمة name تُمرر عبر مُهيئ الهيكل — هكذا يعمل DI (حقن التبعيات) في SwiftUI بدون حاويات DI خارجية. كل معدّل يعيد عرضاً جديداً مع التغيير المطبق، دون تحوير الأصل. هذا ممكن بفضل ثبات أنواع القيم.

ViewBuilder والجمل الشرطية

ViewBuilder هو منشئ نتائج معلّق بـ @resultBuilder يجمع حتى 10 عروض في واحد. داخل body يمكن استخدام if/else و switch و ForEach بدون أغلفة إضافية. ForEach يعمل مع عناصر Identifiable — يُعطى كل عرض معرفاً فريداً للرسوم المتحركة الصحيحة عند الإدراج/الحذف.

إدارة الحالة: @State، @Binding، @ObservedObject

في SwiftUI، تحدد الحالة المحتوى المعروض على الشاشة. عندما تتغير الحالة، يعيد SwiftUI إنشاء body للعرض المعتمد ويقارن النتيجة بالسابقة باستخدام خوارزمية الفرق. لتخزين الحالة تُستخدم property wrappers — كل منها يحل مهمته الخاصة: حالة محلية، اتصال مع عرض فرعي، أو نموذج بيانات خارجي.

swift
struct CounterView: View {
    @State private var count = 0

    var var body: some View {
        VStack {
            Text("العداد: \(count)")
            Button("زيادة") {
                count += 1
            }
        }
    }
}

class UserViewModel: ObservableObject {
    @Published var name = ""
    @Published var age = 0
}

@State يخزّن قيمة محلية بسيطة (Int، String، Bool) داخل هيكل View. ينقل SwiftUI الذاكرة من الهيكل إلى تخزين منفصل — لذلك يمكن تحوير الخاصية مع @State حتى لو كانت View من نوع القيمة. @ObservableObject مخصص للفئات التي تحتوي على خصائص @Published، والتي تُعلم تغييراتها SwiftUI تلقائياً بضرورة إعادة الرسم.

@Binding والاتصال بين الأب والابن

@Binding ينشئ اتصالاً ثنائي الاتجاه مع مصدر البيانات الموجود في العرض الأب. الأب يمرّر $variable (القيمة المسقطة)، والابن يقرأ ويكتب القيمة من خلال binding. وهذا يسمح بنقل إدخال النص أو المفتاح إلى مكون منفصل مع الحفاظ على الحالة في الأب. بدون @Binding، كان كل تغيير يتطلب إغلاق استدعاء لتمرير القيمة الجديدة إلى الأعلى.

قبل iOS 16، كان التنقل في SwiftUI يُبنى على NavigationView — واجهة برمجة قديمة بسلوك معقد على iPad (عرض مقسم، عمود مزدوج). بدءاً من iOS 16، توصي Apple بـ NavigationStack — بديل مبسط بمسارات آمنة النوع. يحدد المطور تعداداً (enum) للمسارات الممكنة، ويدير NavigationStack تلقائياً مكدس الشاشات مع دعم الروابط العميقة والعودة إلى الجذر.

swift
enum Route: Hashable {
    case detail(id: Int)
    case settings
}

struct ContentView: View {
    var var body: some View {
        NavigationStack {
            List {
                NavigationLink("شاشة التفاصيل",
                               value: Route.detail(id: 42))
                NavigationLink("الإعدادات",
                               value: Route.settings)
            }
            .navigationDestination(for: Route.self) { route in
                switch route {
                case .detail(let id): DetailView(id: id)
                case .settings: SettingsView()
                }
            }
        }
    }
}

المسارات المتوافقة مع Hashable تسمح باستخدام أي نوع بيانات لتمرير المعاملات. navigationDestination(for:destination:) يربط نوع المسار بالعرض الهدف. الميزة على تنقل UIKit هي عدم الحاجة إلى إعادة الرسم عند إضافة مسار جديد: يكفي إضافة case إلى enum ومعالج في switch. الروابط العميقة تُعالج عبر processDeepLink على NavigationStack.

التنقل البرمجي

للتنقل البرمجي (بعد تسجيل الدخول، مؤقت، أو استجابة الخادم)، يُستخدم @State مع مُهيئ NavigationLink: NavigationLink(isActive: $isActive). عند تعيين isActive = true، يتم الانتقال دون لمس المستخدم. بديل هو ربط مصفوفة $path في NavigationStack: $path.append(Route.detail(id: 1)).

View Modifier — تخصيص المظهر

Modifier هو طريقة تعيد نسخة معدّلة من العرض. على عكس UIKit، حيث يتم تكوين الخصائص من خلال تحوير عرض موجود، ينشئ SwiftUI قيمة جديدة مع التغيير المطبق. سلسلة المعدّلات تبني الواجهة النهائية من تحويلات متتالية: الخط → الحشو → اللون → الظل → الإيماءة.

توفر Apple أكثر من 200 معدّل مدمج. الأكثر شيوعاً: .font()، .foregroundColor()، .padding()، .background()، .cornerRadius()، .shadow()، .opacity()، .offset(). ترتيب المعدّلات مهم: .padding() قبل .background() يملأ المنطقة بالحشو، بعده — المنطقة الداخلية فقط. المعدّلات المخصصة تُنشأ عبر بروتوكول ViewModifier.

المعدّلات الشرطية والرسوم المتحركة

يمكن تطبيق المعدّلات شرطياً عبر العامل الثلاثي: .foregroundColor(isError ? .red : .primary). للرسوم المتحركة يُستخدم .animation(.easeInOut, value: state) — يرتبط معدّل الرسوم المتحركة بخاصية حالة محددة. عندما تتغير هذه الخاصية، يقوم SwiftUI بتحريك الانتقال بين القيمة القديمة والجديدة. الرسوم المتحركة تعمل مع opacity، offset، scale، rotation، الحجم واللون — لكل خاصية AnimatableParameter مطابق.

للرسوم المتحركة المخصصة، تتوفر .transition (الظهور/الاختفاء) و .matchedGeometryEffect (انتقال سلس لعنصر بين حاويتين). يُستخدم الأخير للرسوم المتحركة البطولية في القوائم: أيقونة في خلية قائمة تتحول بسلاسة إلى صورة كبيرة على شاشة التفاصيل.

SwiftUI مقابل UIKit: مقارنة الأساليب

الاختيار بين SwiftUI و UIKit هو أحد المعضلات الأولى لمطور iOS. كلا الإطارين مدعومان من Apple لكنهما يحلان مشكلة بناء الواجهة بطرق مختلفة جوهرياً: SwiftUI تصريحياً، UIKit أمرياً. يظهر الفرق في إدارة الحالة والتنقل والأداء والتوافق.

الجانبSwiftUIUIKit
النهجتصريحي: ماذا نعرضأمري: كيف نبني
الحالةProperty Wrappers، إعادة رسم تلقائيةيدوياً: reloadData، setNeedsLayout
كود UIمدمج، سلاسل معدّلاتمطول، NSCoder/Storyboard/قيد
الأداءعالي على iOS 17+، خوارزمية فرقذروة على iOS 12–16، تحكم مباشر
النسخة الدنياiOS 15+ (دعم كامل)iOS 2+ (جميع النسخ)

للمشاريع الجديدة ذات النسخة الدنيا iOS 17، توصي Apple بـ SwiftUI كإطار رئيسي. يبقى UIKit ضرورياً للواجهات التي تتطلب تحكماً دقيقاً في العرض (تخطيط UICollectionViewLayout مخصص، مشاهد CAAnimation معقدة) أو دعم iOS 12–14. العديد من المشاريع تستخدم نهجاً هجيناً: SwiftUI عبر UIHostingController يُدمج في تطبيق UIKit، و UIViewRepresentable يسمح باستخدام مكونات UIKit داخل التسلسل الهرمي لـ SwiftUI.

الأسئلة الشائعة

هل يمكن استخدام SwiftUI و UIKit في نفس المشروع؟

نعم، عبر UIHostingController (SwiftUI في UIKit) و UIViewRepresentable (UIKit في SwiftUI). هذا نهج هجين، شائع أثناء الترحيل.

من أي إصدار iOS يجب بدء مشروع SwiftUI؟

iOS 17 يوفر وظائف كاملة: NavigationStack، Observation framework، Swift Charts. iOS 15 هو الحد الأدنى للإنتاج.

لماذا لا يقوم SwiftUI أحياناً بتحديث الواجهة؟

السبب الأكثر شيوعاً هو تغيير خاصية @Published في خيط خلفي. يجب أن يرسل ObservableObject التغييرات على main actor: @MainActor class ViewModel.

كيفية معالجة debounce عند الضغط على زر في SwiftUI؟

استخدم .debounce عبر Combine: Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main).

هل يدعم SwiftUI الإيماءات المخصصة؟

نعم، عبر معدّلات Gesture: DragGesture، LongPressGesture، MagnificationGesture، RotationGesture. ادمجها باستخدام .simultaneousGesture() و .sequenced().

الملخص

  • SwiftUI هو إطار عمل تصريحي من Apple حيث توصف الواجهة كتركيب من هياكل View مع property wrappers لإدارة الحالة.
  • View Protocol مع الخاصية المحوسبة body هو نقطة الدخول الوحيدة لأي عرض. ViewBuilder يجمع حتى 10 عروض في واحد بدون حاويات إضافية.
  • @State و @Binding و @ObservedObject تغطي جميع سيناريوهات إدارة البيانات: حالة محلية، اتصال أب-ابن، ونماذج خارجية.
  • NavigationStack بمسارات enum آمنة النوع استبدل NavigationView، مضيفاً دعم الروابط العميقة والتنقل البرمجي.
  • Modifier هو نمط رئيسي في SwiftUI يسمح بتخصيص مظهر العروض عبر سلسلة استدعاءات دون وراثة.
  • SwiftUI و UIKit يتعايشان عبر UIHostingController و UIViewRepresentable، مما يسمح بالترحيل التدريجي للمشروع.
  • لـ iOS 17+، توصي Apple بـ SwiftUI كإطار رئيسي؛ يبقى UIKit للواجهات المخصصة المعقدة ودعم الإصدارات الأقدم.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا