View Protocol — المفاهيم الأساسية، بروتوكول View في SwiftUI

المؤلف: IT Sectr نُشر: 2026-06-24 وقت القراءة: 7 دق

View Protocol هو البروتوكول الأساسي لـ SwiftUI الذي يجب أن يتوافق معه أي مكون واجهة مرئي. وفقًا لـ Apple Developer Documentation, 2024، يُحدد View عقدًا واحدًا: البنية أو الفئة التي تنفذ هذا البروتوكول يجب أن توفر الخاصية المحسوبة body. من خلال هذا البروتوكول، يبني SwiftUI التسلسل الهرمي الكامل للشاشات من تسميات النص البسيطة إلى هياكل التنقل المعقدة.

الخلاصة

  • View Protocol — بروتوكول SwiftUI الأساسي الذي تلتزم به جميع العناصر المرئية
  • body — المطلب الإلزامي الوحيد للبروتوكول، والذي يعيد المحتوى
  • some View — نوع غير شفاف يخفي النوع الملموس لـ View المُعاد
  • @ViewBuilder — منشئ نتائج يجمع عدة Views في تركيب واحد
  • View — هو نوع قيمة (struct)، مما يضمن تحديثات واجهة قابلة للتنبؤ

ما هو View Protocol في SwiftUI؟

View Protocol هو البروتوكول المركزي لـ SwiftUI الذي يُحدد كيف يصف أي عنصر مرئي محتواه. على عكس UIKit، حيث يرث كل عنصر من UIView عبر الفئات، يستخدم SwiftUI نهجًا موجهًا بالبروتوكولات: أي نوع يتوافق مع بروتوكول View يمكن عرضه على الشاشة.

يتطلب بروتوكول View تنفيذ خاصية محسوبة واحدة body تُرجع بعض المحتوى. ولكن وراء هذه البساطة يكمن نظام تركيب قوي: يمكن لـ body إرجاع أي نوع يتوافق مع View، بما في ذلك البدائيات (Text, Image, Button) والحاويات (VStack, HStack, ZStack) والمكونات المركبة المخصصة.

وفقًا لـ WWDC 2023، يتم بناء أكثر من 95% من جميع الشاشات في تطبيقات SwiftUI من خلال تركيب الهياكل التي تنفذ بروتوكول View. وهذا يجعل View Protocol أساس بنية SwiftUI بأكملها.

Value type مقابل reference type

يتطلب SwiftUI أن يكون View نوع قيمة (value type) (struct)، وليس فئة. هذا قرار معماري رئيسي: أنواع القيم لها عمر افتراضي قابل للتنبؤ، ولا تحتوي على حالة قابلة للتغيير مشتركة، وتسمح لـ SwiftUI بتحديد أي أجزاء التسلسل الهرمي تغيرت وتحتاج إلى إعادة رسم بكفاءة.

إذا حاولت جعل View فئة، فسيصدر المترجم خطأً: بروتوكول View يرث من بروتوكول DynamicViewProperty، الذي يتطلب دلالات القيمة. يمكن للفئات أن تتوافق مع View، لكن هذا يخرق النهج الاصطلاحي ويخسر مزايا التحديثات التلقائية.

body: الخاصية المحسوبة لبروتوكول View

body هو المطلب الإلزامي الوحيد لبروتوكول View. إنها خاصية محسوبة تُرجع المحتوى المعروض على الشاشة. نوع القيمة المُعادة هو some View، مما يعني “نوعًا يتوافق مع View، سيتم تحديده بواسطة المترجم”.

swift
struct GreetingView: View {
    var name: String

    var body: some View {
        VStack {
            Text("Hello, \(name)!")
                .font(.title)
                .foregroundColor(.blue)
            Button("Start") {
                print("Button pressed")
            }
        }
    }
}

كيف يعمل body: يستدعي SwiftUI الخاصية body في كل مرة تتغير فيها حالة التطبيق ويتطلب إعادة رسم. يقارن الإطار الشجرة الجديدة لـ Views مع القديمة ويطبق فقط التغييرات الضرورية (diffing). هذا نهج تصريحي بالكامل — أنت تصف ما يجب عرضه، ويتولى SwiftUI كيفية تنفيذه.

تفصيل مهم: body يجب ألا يكون له آثار جانبية. يتم استدعاؤه مرات عديدة خلال عمر التطبيق، وإذا قام body بتعديل حالة خارجية — فإنه يؤدي إلى سلوك غير متوقع. للآثار الجانبية، استخدم task أو onChange أو DispatchQueue.

حد عدد العناصر

يفرض SwiftUI قيدًا: body يمكنه إرجاع عنصر جذر واحد فقط. إذا كنت بحاجة إلى عرض عدة عناصر في نفس المستوى، فلفها في حاوية — VStack أو HStack أو ZStack أو Group. مع ظهور @ViewBuilder، أصبح هذا القيد أقل وضوحًا، ولكن من الناحية المفاهيمية، يعيد body دائمًا View واحدًا.

some View: النوع غير الشفاف في البروتوكول

some View هو صياغة النوع غير الشفاف (opaque type) التي تم تقديمها في Swift 5.1 خصيصًا لـ SwiftUI. تعني أن دالة أو خاصية تُرجع نوعًا ملموسًا يتوافق مع بروتوكول View، لكن الكود المستدعي لا يعرف ولا يحتاج إلى معرفة أي نوع بالضبط يتم إرجاعه.

مترجم Swift يُثبت النوع الملموس في وقت الترجمة لكل تنفيذ body، لكنه يخفيه عن العالم الخارجي. هذا يسمح لـ SwiftUI بتحسين التسلسل الهرمي لـ Views من خلال معرفة الأنواع الدقيقة لجميع المكونات، مع إعطاء المطور المرونة لتغيير التنفيذ دون تغيير التوقيع.

swift
struct ContentView: View {
    var body: some View {
        Text("Hello, World!") // Compiler knows this is Text
    }
}

لماذا some View وليس View فقط؟ إذا كان body يُرجع View فقط (كبروتوكول)، فلن يتمكن SwiftUI من تحديد النوع الملموس في وقت الترجمة. هذا يضيف عبئًا إضافيًا للتغليف في حاوية وجودية (existential container). some View يعطي المترجم معلومات كافية للتحسين مع الحفاظ على مرونة البروتوكول.

قيود some View

القيد الرئيسي هو body يجب أن يُرجع نفس النوع. لا يمكنك إرجاع Text في فرع من الشرط و Image في فرع آخر بدون أغلفة خاصة (AnyView أو Group أو @ViewBuilder). يتحقق المترجم من هذا في وقت الترجمة: جميع مسارات الإرجاع الممكنة يجب أن يكون لها نفس النوع.

لتجاوز هذا القيد، يُستخدم @ViewBuilder (ينشئ نوع TupleView واحدًا) أو Group (الذي يُرجع أيضًا نوعًا واحدًا) أو AnyView (يمسح النوع لكنه يضيف عبئًا). يجب استخدام AnyView فقط عندما لا تكون الخيارات الأخرى ممكنة، لأنه يعطل تحسينات SwiftUI.

@ViewBuilder: تجميع عدة Views

@ViewBuilder هو منشئ نتائج (result builder) يسمح توجيهه بتجميع عدة Views في تركيب واحد بدون حاويات متداخلة. @ViewBuilder يلف تلقائيًا عدة تعبيرات في tuple (TupleView) أو يطبق منطقًا شرطيًا (If / else / switch) مع نوع الإرجاع الصحيح.

swift
struct DashboardView: View {
    var isLoggedIn: Bool

    @ViewBuilder
    var body: some View {
        if isLoggedIn {
            Text("Welcome!")
                .font(.largeTitle)
            ProfileCard()
        } else {
            LoginButton()
                .padding()
        }
    }
}

كيف يعمل @ViewBuilder: يحول المترجم كل كتلة كود داخل @ViewBuilder إلى استدعاءات للطرق الثابتة buildBlock و buildEither و buildOptional إلخ. إذا كانت الكتلة تحتوي على عدة تعبيرات، تُلف في TupleView. إذا كانت الكتلة تحتوي على منطق شرطي، يُنشئ المترجم ConditionalContent، مخفيًا نوع الفرع.

يفرض @ViewBuilder قيدًا: حتى 10 عناصر في الكتلة الواحدة (حد TupleView). إذا كنت بحاجة إلى تجميع أكثر من عشرة عناصر، استخدم Group أو ForEach أو قسم إلى مكونات فرعية. هذا القيد موجود لأن Swift يُنشئ حملًا زائدًا منفصلًا لـ buildBlock لكل عدد من 1 إلى 10.

تركيب View والمُعدّلات

التركيب (Composition) مبدأ رئيسي في SwiftUI: يتم بناء الواجهات المعقدة من مكونات View صغيرة وقابلة لإعادة الاستخدام. كل مكون ينفذ بروتوكول View ويكون مسؤولًا عن جزئه من الشاشة. تُطبق المُعدّلات (font, padding, foregroundColor) على View وتُعيد View جديدًا بإعدادات معدلة.

المُعدّلات في SwiftUI ليست تغييرات، بل إنشاء غلاف جديد حول View الأصلي. كل مُعدّل يُعيد نوعًا جديدًا (ModifiedContent)، مما يسمح لـ SwiftUI ببناء شجرة مُعدّلات وإعادة رسم الأجزاء المتغيرة فقط بكفاءة. ترتيب تطبيق المُعدّلات مهم: ترتيبات مختلفة تعطي نتائج بصرية مختلفة.

swift
Text("Hello, SwiftUI!")
    .font(.title)        // ModifiedContent
    .padding()           // ModifiedContent<..., PaddingModifier>
    .background(.yellow) // ModifiedContent<..., BackgroundModifier>
    .cornerRadius(8)    // ModifiedContent<..., CornerRadiusModifier>

تحسين الأداء: لا يقارن SwiftUI قيم View الملموسة بل هويتها من خلال آلية الهوية (id, ForEach, الهوية المستقرة للهياكل). إذا لم يتغير هيكل View، لا يتم استدعاء body. يتم تحقيق ذلك من خلال مقارنة Equatable وآلية PreferenceKey لنقل البيانات لأعلى التسلسل الهرمي.

للحصول على تركيب فعال، يُوصى بتقسيم الشاشات المعقدة إلى مكونات فرعية مستقلة، لكل منها حالته الدنيا. هذا يسمح لـ SwiftUI بإعادة رسم الأجزاء المتغيرة فقط من التسلسل الهرمي، وليس الشاشة بأكملها.

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

ما هو View Protocol في SwiftUI؟

View Protocol هو بروتوكول SwiftUI الأساسي الذي يجب أن يتوافق معه أي مكون معروض. يتطلب خاصية body محسوبة واحدة تُرجع المحتوى. جميع عناصر SwiftUI القياسية — Text, Button, Image, VStack — تنفذ هذا البروتوكول.

لماذا يجب أن يكون View في SwiftUI بنية (struct) وليس فئة؟

يستخدم SwiftUI دلالات القيمة (value semantics) لتحديثات واجهة قابلة للتنبؤ. الهياكل لا تحتوي على حالة قابلة للتغيير مشتركة، مما يسمح لـ SwiftUI بمقارنة التسلسل الهرمي القديم والجديد لـ Views بكفاءة وإعادة رسم العناصر المتغيرة فقط. الفئات تُعطل هذا التحسين.

ماذا تُرجع خاصية body في بروتوكول View؟

body تُرجع some View — نوعًا غير شفاف يخفي التنفيذ الملموس. في الواقع تُرجع أي نوع يتوافق مع View: Text, Image, VStack, هياكل مخصصة. يُثبت المترجم النوع الملموس في وقت الترجمة للتحسين.

ما الفرق بين some View و AnyView؟

some View هو نوع غير شفاف مع تثبيت النوع الملموس في وقت الترجمة. AnyView هو مسح نوع (type erasure) يلف أي View في حاوية واحدة. some View أكثر كفاءة؛ AnyView يضيف عبئًا ويُستخدم فقط عندما يكون التبديل الديناميكي للنوع مطلوبًا.

كم عدد Views التي يمكن وضعها في كتلة @ViewBuilder واحدة؟

حتى 10 عناصر — هذا هو حد TupleView، الذي يُنشئ buildBlock للأعداد من 1 إلى 10. إذا كنت بحاجة إلى عناصر أكثر، استخدم Group أو ForEach أو List أو قسم إلى مكونات فرعية. هذا القيد موجود على مستوى مترجم Swift.

الملخص

  • View Protocol هو أساس SwiftUI: أي عنصر معروض يجب أن يتوافق مع هذا البروتوكول
  • body هي الخاصية الوحيدة المطلوبة، والتي تُرجع المحتوى من خلال النوع غير الشفاف some View
  • some View هو نوع غير شفاف يسمح للمترجم بتحسين التسلسل الهرمي لـ Views
  • @ViewBuilder هو منشئ نتائج لتجميع عدة Views في كتلة واحدة بدون حاويات إضافية
  • View دائمًا نوع قيمة (struct)، مما يضمن تحديثات قابلة للتنبؤ و diffing
  • المُعدّلات لا تُغير View بل تُنشئ غلافًا جديدًا ModifiedContent
  • تركيب مكونات View الصغيرة هو نمط رئيسي لبنية SwiftUI

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

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

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

اقرأ أيضًا