كيف تجتاز مقابلة Swift: أهم الأسئلة المتقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

كيف تجتاز مقابلة Swift: أهم الأسئلة المتقدمة



مقابلة منصب مطور iOS ليست مجرد اختبار لمعرفة UIKit و SwiftUI. على المستوى المتقدم، يريد مسؤولو التوظيف والقادة التقنيون التأكد من أنك تفهم كيفية عمل الذاكرة، والفرق بين class و struct في سياق العد المرجعي، وكيفية بناء بنية سليمة باستخدام البروتوكولات، وكيفية إدارة التزامن غير المتزامن. في هذه المقالة، سنناقش المواضيع الرئيسية التي تظهر غالبًا في مقابلات Swift لمستوى Middle و Senior.



1. إدارة الذاكرة و ARC (العد المرجعي التلقائي)



ARC هو أحد أكثر المواضيع شيوعًا في المقابلات. لا تحتاج فقط إلى معرفة النظرية، بل يجب أن تكون قادرًا على شرح كيفية تجنب تسرب الذاكرة.



1.1. كيف يعمل ARC وما هي دورات المراجع القوية؟



يقوم ARC تلقائيًا بحساب عدد المراجع القوية لكائن من الفئة. بمجرد أن يصبح العداد صفرًا، يتم حذف الكائن من الذاكرة. تنشأ المشكلة عندما يشير كائنان إلى بعضهما البعض بقوة - تتشكل دورة (retain cycle).



class Parent {    var child: Child?}

class Child { var parent: Parent? // مرجع قوي بالعكس}

var parent: Parent? = Parent()var child: Child? = Child()parent?.child = childchild?.parent = parent// لن يتم تحرير أي من الكائنين أبدًا


1.2. كيف تكسر الدورة؟



استخدم weak أو unowned. weak هو مرجع اختياري يصبح تلقائيًا nil عند حذف الكائن. unowned هو مرجع غير اختياري، ولكنه يفترض أن الكائن سيعيش على الأقل بقدر عمر الكائن المرجعي.



class Child {    weak var parent: Parent?  // مرجع ضعيف}


1.3. كيف يعمل ARC مع الإغلاقات؟



تلتقط الإغلاقات المتغيرات الخارجية. إذا تم تخزين الإغلاق كخاصية للفئة، وتم استخدام self بداخله، تنشأ دورة. الحل هو استخدام [weak self] أو [unowned self].



class NetworkManager {    var completionHandler: (() -> Void)?        func fetchData() {        completionHandler = { [weak self] in            guard let self = self else { return }            self.processData()        }    }        func processData() { }}


2. الإغلاقات: escaping مقابل non-escaping



فهم الفرق بين الإغلاقات escaping و non-escaping هو نقطة إلزامية لأي منصب متقدم.



2.1. ما هو الإغلاق escaping؟



يسمى الإغلاق escaping إذا كان يمكن استدعاؤه بعد العودة من الدالة. افتراضيًا، جميع الإغلاقات هي non-escaping - يعرف المترجم أنها ستنفذ داخل جسم الدالة. بالنسبة للعمليات غير المتزامنة (مثل طلبات الشبكة)، يجب تحديد @escaping صراحةً.



func performAsyncTask(completion: @escaping (String) -> Void) {    DispatchQueue.global().async {        // محاكاة مهمة طويلة        sleep(2)        completion("تم")    }}


2.2. لماذا الإغلاقات non-escaping أسرع؟



يحسن المترجم الإغلاقات non-escaping - يمكنه عدم نسخها إلى الكومة (heap)، بل تخزينها على المكدس. كما يمكنه تجنب حساب المراجع، لأن عمر الإغلاق محدود باستدعاء الدالة.



3. الأدوية العامة والبروتوكولات ذات الأنواع المرتبطة (PAT)



الأدوية العامة هي أساس Swift. في المقابلة، قد يُطلب منك كتابة بنية عامة أو شرح كيفية عمل البروتوكولات ذات الأنواع المرتبطة.



3.1. اكتب طابورًا عامًا (Queue)



struct Queue<T> {    private var elements: [T] = []        mutating func enqueue(_ value: T) {        elements.append(value)    }        mutating func dequeue() -> T? {        guard !elements.isEmpty else { return nil }                

المدونات

توصيات الكتب