Opaque Type: ما هو، some و any في Swift

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

Opaque Type (النوع غير الشفاف) هي آلية في Swift تسمح للدالة بإرجاع قيمة من نوع ما دون الكشف عن النوع المحدد للكود المستدعي. الكلمة المفتاحية some في نوع الإرجاع هي المثال الأكثر شهرة: some View في SwiftUI تعني «تُرجع الدالة نوعاً ما يمتثل لـ View، لكن تحديد أي نوع هو تفصيل تنفيذي». يحافظ opaque type على هوية النوع (على عكس البروتوكول كنوع)، مما يسمح للمترجم بتحسين الكود ويضمن اتساق النوع المُعاد. وفقاً لـ Swift Book, 2025، تحل الأنواع غير الشفافة مشكلة البروتوكولات ذات الأنواع المرتبطة، مما يسمح بإرجاع قيم هذه البروتوكولات من الدوال.

الخلاصة

  • Opaque Type — نوع إرجاع يخفي التنفيذ المحدد عن الكود المستدعي
  • some — الكلمة المفتاحية لإعلان opaque type في موضع الإرجاع
  • هوية النوع محفوظة: المترجم يعرف النوع المحدد، على عكس any
  • SwiftUI تستخدم some View كطريقة قياسية لإعلان body
  • قيد: الدالة التي تستخدم some يجب أن تُرجع نفس النوع المحدد من جميع الفروع

ما هو Opaque Type في Swift؟

Opaque Type هو نوع إرجاع يُعلن بالكلمة المفتاحية some ويخفي التنفيذ المحدد عن الكود المستدعي. الطرف المستدعي يعرف فقط أن القيمة المُعادة تمتثل لبروتوكول معين، لكنه لا يعرف بالضبط أي نوع يقف وراء some. في الوقت نفسه، يعرف المترجم النوع الدقيق ويستخدمه للتوزيع الثابت والتحسين.

المشكلة التي يحلها Opaque Type

قبل ظهور الأنواع غير الشفافة في Swift 5.1 (SE-0244)، كان من المستحيل إرجاع بروتوكول ذي أنواع مرتبطة من دالة دون غلاف تغليف. على سبيل المثال، بروتوكول Equatable له نوع مرتبط، ولم تستطع الدالة ببساطة إرجاع Equatable — كان المترجم يظهر خطأ «لا يمكن استخدام البروتوكول إلا كقيد عام». حل opaque type هذه المشكلة.

swift
func makeInt() -> some Equatable {
    return 42
}

func makeString() -> some Equatable {
    return "Hello"
}

// يعرف المترجم أن makeInt تُرجع Int
// makeInt() == makeString() — ❌ خطأ، أنواع مختلفة

كلتا الدالتين تُرجعان some Equatable، لكن الأنواع المحددة مختلفة: Int و String. محاولة مقارنتهما بـ == ستسبب خطأ في الترجمة لأن opaque type يضمن أن استدعاءً معيناً يُرجع نفس النوع، لكن ليس عبر دوال مختلفة. هذه ميزة وليس خطأ: opaque type يحافظ على هوية النوع حيث يخسرها البروتوكول كنوع (any Equatable).

Opaque Type vs Generic: ما الفرق

Generic و Opaque Type وجهان لعملة واحدة. تسمح الأنواع العامة (generics) للكود المستدعي باختيار النوع، بينما يسمح opaque type للدالة بإخفاء النوع عن الكود المستدعي. الفرق في اتجاه التحكم.

الخاصيةGeneric Opaque some
من يختار النوعالكود المستدعيالدالة/الطريقة
هوية النوعمحفوظة (مستقرة)محفوظة (مستقرة)
عدد فروع الإرجاعواحد (عبر العام)نفس النوع في جميع الفروع
الاستخدامالخوارزميات، هياكل البياناتSwiftUI، طرق المصنع

Generic — الاختيار من الخارج

في دالة عامة، المستدعي يقرر أي نوع يستخدم. يجب أن تعمل الدالة مع أي T يحقق القيود. بالنسبة لـ opaque type، لا يعرف المستدعي النوع المحدد — التنفيذ هو من يتخذ القرار.

swift
// Generic: المستدعي يختار النوع
func identity<T>(_ value: T) -> T { value }
let x: Int = identity(42)

// Opaque: الدالة تخفي النوع
func makeSomeEquatable() -> some Equatable { 42 }
let y = makeSomeEquatable()

الاختيار بين generic و opaque type يعتمد على القصد. إذا كان الكود المستدعي يجب أن يختار النوع، استخدم الأنواع العامة. إذا كانت الدالة يجب أن تخفي تفاصيل التنفيذ، استخدم some. اختارت SwiftUI some View تحديداً لأن body يجب أن يكون مرناً داخلياً لكن مستقراً خارجياً.

الكلمة المفتاحية some واستخداماتها

some هي كلمة مفتاحية في Swift أُدخلت في Swift 5.1 (SE-0244). تُستخدم في موضع الإرجاع لإعلان opaque type، وكذلك في المعاملات (SE-0341) والخصائص. تضمن some أن النوع المحدد مستقر ومعروف للمترجم لكنه مخفي عن الكود الخارجي.

some في معاملات الدالة

اعتباراً من Swift 5.7، يمكن استخدام some ليس فقط في موضع الإرجاع ولكن أيضاً في المعاملات. some Equatable في معامل يعني «هذه الدالة تقبل أي نوع Equatable، لكن جميع الاستدعاءات داخل جسم محدد ترى نفس النوع».

swift
func areEqual(_ a: some Equatable, _ b: some Equatable) -> Bool {
    // a و b — أنواع مختلفة محتملة، == لن يعمل مباشرة
    return isEqual(a, b)
}

func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
    return a == b
}

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

الكلمة المفتاحية any والأنواع الوجودية

any هي كلمة مفتاحية في Swift 5.6+ للإعلان صراحة عن الأنواع الوجودية (البروتوكول كنوع). على عكس some، يمحو any هوية النوع: لا يعرف المترجم أي نوع محدد يختبئ وراء البروتوكول. هذا يوفر مرونة (يمكنك تخزين أنواع مختلفة في مصفوفة واحدة)، لكن على حساب الأداء.

some vs any: تحليل مقارن

some — تعدد أشكال ثابت: يعرف المترجم النوع المحدد، يستخدم التوزيع المباشر ويمكنه تضمين الكود. any — تعدد أشكال ديناميكي: يُستخدم جدول الطرق الافتراضية (حاوية وجودية)، مما يضيف غير مباشرة.

swift
protocol Drawable {
    func draw()
}

// some: النوع الثابت معروف
func makeDrawable() -> some Drawable {
    return Circle() // نوع إرجاع واحد
}

// any: ديناميكي، يمكن تخزين أنواع مختلفة
var shapes: [any Drawable] = [Circle(), Square()]
shapes.append(Triangle())

الاختيار بين some و any هو مقايضة بين الأداء والمرونة. Some أسرع لكنه يقتصر على تنفيذ واحد. Any أكثر مرونة (يمكنك خلط الأنواع) لكنه أبطأ بسبب التوزيع الديناميكي. في SwiftUI، يستخدم body دائماً some View لأن body لكل View هو نوع محدد واحد.

Opaque Type في البروتوكولات ذات الأنواع المرتبطة

Opaque Type يحل مشكلة أساسية في Swift: البروتوكولات ذات الأنواع المرتبطة (PAT) لا يمكن استخدامها مباشرة كنوع. لا تستطيع الدالة ببساطة إرجاع Collection — يطلب المترجم تحديد Element. some Collection تحل هذا بإخفاء النوع المرتبط.

إرجاع PAT عبر some

بدون opaque type، إرجاع Collection كان يتطلب استخدام نوع محدد (Array) أو محو النوع (AnyCollection). some Collection يوفر نقطة وسط: المترجم يعرف التنفيذ المحدد، الكود المستدعي لا يعرفه.

swift
func makeReversedCollection<T>(
    of array: [T]
) -> some Collection {
    return array.reversed()
}

let result = makeReversedCollection(of: [1, 2, 3])
// result — ReversedCollection>, hidden from caller
for item in result {
    print(item)
}

يمكن تكرار result، لكن لا يمكن الوصول مباشرة إلى خصائص ReversedCollection. هذا يحمي التغليف: إذا استبدلت لاحقاً reversed() بطريقة أخرى ذات تنفيذ مختلف، لن يتعطل الكود المستدعي. يمنحك opaque type حرية تغيير التنفيذ دون تغيير API.

أمثلة عملية لـ some View في SwiftUI

some View هو الاستخدام الأكثر شهرة لـ opaque type. كل View في SwiftUI تعلن body كـ some View. هذا يعني أن body يُرجع نوعاً محدداً من View، لكن المطور لا يحتاج للتفكير في ما هو بالضبط — TupleView، Group، ModifiedContent أو أي نوع آخر من الإطار.

كيف تستخدم SwiftUI some View

بدون opaque type، كان يجب على body إرجاع نوع محدد، مثلاً ModifiedContent<Button<Text>, Padding>، وهو أمر غير عملي. some View يخفي هذا التعقيد. يستنتج المترجم النوع الدقيق لـ body تلقائياً في وقت الترجمة.

swift
struct ContentView: View {
    var body: some View {
        VStack {
            Text("مرحباً")
                .font(.title)
            Button("اضغط علي") {
                print("تم الضغط")
            }
        }
        .padding()
    }
}

يستنتج المترجم body كـ ModifiedContent<VStack<TupleView<(Text, Button<Text>)>>, Padding>. المطور يرى some View. إذا غيرت التخطيط من VStack إلى HStack، سيعيد المترجم استنتاج النوع تلقائياً — بدون أي تعديلات يدوية. هذا هو سحر opaque type: يركز المطور على منطق الواجهة، وليس على أنواع التركيب.

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

ما هو Opaque Type في Swift؟

Opaque Type هو نوع يُعلن بالكلمة المفتاحية some يخفي التنفيذ المحدد عن الكود المستدعي. يعرف المترجم النوع الدقيق، لكن المطور الذي يستخدم الدالة يرى فقط البروتوكول.

كيف يختلف some عن any في Swift؟

some هو opaque type بهوية ثابتة: يعرف المترجم النوع المحدد. any هو نوع وجودي بتوزيع ديناميكي: هوية النوع ممحاة. Some أكثر أداءً، any أكثر مرونة.

لماذا تستخدم SwiftUI some View؟

some View يخفي النوع المحدد المعقد لـ body الذي يستنتجه المترجم تلقائياً. هذا يحرر المطور من كتابة النوع الدقيق المكون من أغلفة عامة (VStack, Group, ModifiedContent).

هل يمكن استخدام some في معاملات الدالة؟

نعم, اعتباراً من Swift 5.7. Some في المعاملات هو سكر نحوي على معامل عام. يبسط إعلان الدوال، خاصة عند العمل مع البروتوكولات حيث كل معامل some لا يتطلب منفصلاً.

ماذا يحدث إذا أرجعت أنواعاً مختلفة من دالة some؟

سيظهر المترجم خطأ: يتطلب opaque type أن جميع فروع الإرجاع تُرجع نفس النوع المحدد. هذا مقصود للحفاظ على هوية النوع. إذا كنت بحاجة لإرجاع أنواع مختلفة، استخدم any.

الملخص

  • Opaque Type — يخفي النوع المحدد للقيمة المُعادة مع الحفاظ على هويته على مستوى المترجم
  • الكلمة المفتاحية some تُستخدم لإعلان opaque type في موضع الإرجاع والمعاملات
  • Generic vs Opaque: المستدعي يختار النوع للعام، التنفيذ يختار لـ opaque
  • any — نوع وجودي بتوزيع ديناميكي، some — تعدد أشكال ثابت
  • SwiftUI some View — حالة الاستخدام الرئيسية: يخفي النوع المعقد لـ body عن المطور
  • Opaque type يحل مشكلة إرجاع البروتوكولات ذات الأنواع المرتبطة (PAT) من الدوال

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

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

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

اقرأ أيضًا