مقدمة: لماذا تحتاج إلى معرفة نوع المتغير في Swift؟
\nهل سبق لك أن كتبت كودًا بلغة Swift وفجأة تساءلت: "ما هو نوع هذا المتغير؟" خاصة عند العمل مع Any، أو الأدوية (Generics)، أو الوراثة المعقدة. الأمر يشبه محاولة تخمين ما بداخل صندوق دون فتحه. لكن في Swift، هناك أدوات قوية تسمح لك بالنظر إلى الداخل وتحديد نوع أو كلاس المتغير بدقة.
في هذه المقالة، سنشرح كيفية عرض نوع المتغير في Swift باستخدام type(of:)، Mirror، String(describing:) وحتى dynamicType القديم الجيد (نعم، لا يزال موجودًا في الكود القديم). ستتعلم ليس فقط طباعة النوع، بل أيضًا استخدامه في مشاريع حقيقية: لتصحيح الأخطاء، وتسجيل السجلات، والتحقق من الأنواع في وقت التشغيل، والعمل مع البروتوكولات.
المقالة مكتوبة للموقع التعليمي pythonlib.ru ومُكيَّفة للمبتدئين والمطورين ذوي الخبرة. هيا بنا!
\n\n1. الطريقة الأبسط: type(of:)
\nالطريقة الأكثر شيوعًا وصحة لمعرفة نوع المتغير في Swift هي استخدام الدالة العامة type(of:). تقوم هذه الدالة بإرجاع النوع الفوقي (MetaType) للقيمة المُمررة.
مثال:
\nlet name = "آنا"\nlet age = 25\nlet price: Double = 99.99\nlet isActive = true\n\nprint(type(of: name)) // String\nprint(type(of: age)) // Int\nprint(type(of: price)) // Double\nprint(type(of: isActive)) // Bool\n\nلاحظ أن type(of:) يعمل مع أي نوع — الهياكل (Structs)، الكلاسات (Classes)، التعدادات (Enums)، والإغلاقات (Closures). حتى مع القيم الاختيارية:
var optionalValue: String? = "Hello"\nprint(type(of: optionalValue)) // Optional<String>\n\n\nلماذا type(of:) هو الخيار الأفضل؟
\n- \n
- يعمل مع أنواع القيم (الهياكل، التعدادات) وأنواع المراجع (الكلاسات). \n
- يدعم البروتوكولات والأدوية (Generics). \n
- لا يتطلب تحديد النوع صراحة في الكود. \n
- يُرجع النوع الديناميكي الدقيق (مع مراعاة الوراثة). \n
2. الطريقة التقليدية: String(describing:)
\nأحيانًا لا تحتاج فقط إلى معرفة النوع، بل إلى تحويله إلى سلسلة نصية لعرضها في السجل أو الواجهة. String(describing:) يقوم بهذه المهمة بشكل ممتاز:
let value: Any = 42\nprint(String(describing: type(of: value))) // Int\n\nيمكن دمجه مع type(of:) لتسجيل جميل:
func logType(_ value: Any) {\n let typeName = String(describing: type(of: value))\n print("[LOG] النوع: \\(typeName)، القيمة: \\(value)")\n}\nlogType(3.14) // [LOG] النوع: Double، القيمة: 3.14\n\n\n3. العمل مع الكلاسات: dynamicType و Mirror
\nقبل Swift 3، كان يُستخدم الخاصية dynamicType. لا تزال متاحة للتوافق مع الإصدارات السابقة، لكنها مُهمَلة رسميًا. ومع ذلك، قد تجدها في المشاريع القديمة:
class Animal {}\nclass Dog: Animal {}\n\nlet pet: Animal = Dog()\nprint(pet.dynamicType) // Dog (بناء جملة قديم)\n\nالبديل الحديث هو type(of:):
print(type(of: pet)) // Dog\n\n\nMirror: نظرة أعمق
\nإذا كنت بحاجة إلى معرفة ليس فقط النوع، بل أيضًا بنية الكائن (مثل أسماء الخصائص)، استخدم Mirror:
struct User {\n let name: String\n let age: Int\n}\n\nlet user = User(name: "إيفان", age: 30)\nlet mirror = Mirror(reflecting: user)\nprint(mirror.subjectType) // User\nfor child in mirror.children {\n print("\\(child.label ?? ""): \\(child.value) (\\(type(of: child.value)))")\n}\n// الإخراج:\n// name: إيفان (String)\n// age: 30 (Int)\n\nهذا مفيد بشكل خاص لتصحيح أخطاء التسلسلات الهرمية المعقدة أو عند العمل مع الانعكاس (Reflection).
\n\n4. تحديد الكلاس لـ Any و AnyObject
\nفي Swift، غالبًا ما نواجه النوع Any — يمكنه تخزين قيمة من أي نوع. لمعرفة النوع المحدد