كيفية اجتياز مقابلة Swift: المستوى المتقدم
\n\nمقابلة منصب مطور iOS كبير (Senior iOS) أو قائد فريق (Team Lead) ليست مجرد اختبار لمعرفة بناء الجملة. يريد المحاورون رؤية فهم عميق للبنية الداخلية لـ Swift، والقدرة على تصميم البنية وتجنب المخاطر. في هذه المقالة، سنستعرض 4 مجموعات من الأسئلة المتقدمة التي تظهر غالبًا في المقابلات. كل مجموعة مصحوبة بأمثلة كود وشروحات ستساعدك على الإجابة بثقة على أي سؤال.
\n\n1. العد المرجعي التلقائي (ARC) وإدارة الذاكرة
\n\nARC هو أحد المواضيع الرئيسية. قد يسأل المحاور عن دورات المراجع القوية (strong reference cycles) وطرق كسرها.
سؤال: ما هي قائمة الالتقاط (capture list) وكيف تساعد في تجنب دورة الاحتفاظ (retain cycle) في الإغلاقات؟
\n\nالإغلاقات في Swift هي أنواع مرجعية. إذا التقط الإغلاق self (على سبيل المثال، خاصية من صنف)، وكان الكائن نفسه يخزن هذا الإغلاق، تنشأ دورة. الحل هو استخدام capture list مع المعدلات [weak self] أو [unowned self].
class NetworkManager {\n var onComplete: (() -> Void)?\n\n func fetchData() {\n // خطير: التقاط مرجع قوي\n onComplete = {\n self.processData() // retain cycle!\n }\n\n // صحيح: التقاط ضعيف\n onComplete = { [weak self] in\n guard let self = self else { return }\n self.processData()\n }\n }\n\n func processData() { print("Processing...") }\n deinit { print("NetworkManager deallocated") }\n}\n\nهام: استخدم unowned self فقط إذا كنت متأكدًا من أن الكائن سيكون موجودًا عند استدعاء الإغلاق. وإلا، استخدم weak self.
2. الأدوية العامة (Generics) والبروتوكولات مع النوع المرتبط (associatedtype)
\n\nالمستوى المتقدم يعني القدرة على كتابة كود عام وفهم قيود البروتوكولات ذات الأنواع المرتبطة.
\n\nسؤال: ما الفرق بين البروتوكول مع associatedtype والبروتوكول مع generics؟ كيف تستخدم الأنواع المعتمة (Opaque Types) (some)؟
\n\nالبروتوكول مع associatedtype لا يمكن استخدامه كنوع مستقل. لإخفاء النوع المحدد، تُستخدم الكلمة المفتاحية some (نوع الإرجاع المعتم)، والتي ظهرت في Swift 5.1.
// بروتوكول مع نوع مرتبط\nprotocol Container {\n associatedtype Item\n mutating func append(_ item: Item)\n var count: Int { get }\n}\n\n// تنفيذ\nstruct IntBox: Container {\n typealias Item = Int\n private var items: [Int] = []\n mutating func append(_ item: Int) { items.append(item) }\n var count: Int { items.count }\n}\n\n// دالة تُرجع "some Container" — النوع المحدد مخفي\nfunc makeContainer() -> some Container {\n return IntBox()\n}\n\n// استخدام\nvar box = makeContainer()\nbox.append(42)\nprint(box.count) // 1\n\nهذا الأسلوب يسمح بتغيير التنفيذ بمرونة دون تغيير الكود المستدعي. غالبًا ما يُسأل عنه في سياق SwiftUI ونمط Builder.
\n\n3. تعدد المهام: GCD و OperationQueue
\n\nمعرفة Grand Central Dispatch والعمليات هي نقطة إلزامية لأي مطور iOS. الأسئلة المتقدمة تتعلق بالجمود (deadlock)، أمان الخيوط (thread safety)، والأولويات.
\n\nسؤال: كيف تتجنب سباق البيانات (Data Race) عند العمل مع بيانات مشتركة من خيوط مختلفة؟
\n\nيحدث سباق البيانات عندما يقرأ خيطان ويكتبان في نفس منطقة الذاكرة في وقت واحد دون مزامنة. الحل هو استخدام قائمة انتظار متسلسلة أو قفل.
\n\nclass ThreadSafeCounter {\n private var count = 0\n // قائمة انتظار متسلسلة للمزامنة\n private let queue = DispatchQueue(label: "com.example.counter")\n\n func increment() {\n queue.sync {\n count += 1\n }\n }\n\n func getCount() -> Int {\n return queue.sync