حقن التبعية (Dependency Injection) في Swift: دليل كامل للمبتدئين

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

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

ابدأ الدورة

مقدمة: لماذا يحتاج كودك إلى حقن التبعية؟



كل مطور iOS يواجه موقفاً يصبح فيه الفصل "ضخماً" ومرتبطاً بشكل صارم بتطبيقات محددة. تغير فصلاً واحداً، وتضطر لإعادة كتابة عشرات الفصول الأخرى. هل هذا مألوف؟ هذه هي المشكلة الكلاسيكية للاقتران القوي (tight coupling).



حقن التبعية (Dependency Injection - DI) هو نمط تصميم يحل هذه المشكلة. بدلاً من أن يقوم الكائن بإنشاء تبعياته بنفسه، يتم "حقنها" من الخارج. هذا يجعل الكود مرناً، قابلاً للاختبار، ومتوافقاً مع مبادئ SOLID (خاصة مبدأ عكس التبعية).



في هذه المقالة، سنشرح ما هو DI في Swift، وما هي طرق تنفيذه، وكيف يبسط حياة مطور iOS/macOS. سنستخدم أمثلة بسيطة مفهومة حتى للمبتدئين.



ما هو حقن التبعية؟ مثال بسيط



تخيل أنك تخبز بيتزا. الخيار بدون DI: أنت تزرع القمح بنفسك، تصنع الدقيق، تحلب البقرة للجبن. هذا اقتران قوي. الخيار مع DI: أنت فقط تطلب المكونات (التبعيات) من المورد. لا يهمك كيف صُنع الدقيق - المهم النتيجة.



في البرمجة نفس الشيء. لنفترض أن لدينا فئة OrderService ترسل الطلبات عبر البريد الإلكتروني:



// ❌ بدون DI - اقتران قويclass OrderService {    let mailer = Mailer() // ينشئ التبعية بنفسه

func process(order: Order) { mailer.send(email: "طلب جديد: \\(order.id)") }}


المشكلة: لا يمكننا استبدال Mailer بنسخة اختبارية. الفئة OrderService "تعرف" أكثر من اللازم.



// ✅ مع DI - يتم حقن التبعيةclass OrderService {    let mailer: MailerProtocol // يعتمد على التجريد وليس التنفيذ الملموس

init(mailer: MailerProtocol) { // الحقن عبر المُهيئ self.mailer = mailer }

func process(order: Order) { mailer.send(email: "طلب جديد: \\(order.id)") }}


الآن يمكننا تمرير أي كائن يتوافق مع بروتوكول MailerProtocol - سواء كان بريداً حقيقياً أو "وهمياً" للاختبارات.



ثلاث طرق رئيسية لحقن التبعيات في Swift



هناك ثلاث طرق شائعة لنقل التبعية إلى فئة. دعنا نستعرض كل منها.



1. الحقن عبر المُهيئ (Constructor Injection)

الطريقة الأكثر شيوعاً والمفضلة. يتم تمرير التبعية عند إنشاء الكائن. هذا يضمن أن الكائن دائماً في حالة صالحة.



protocol NetworkServiceProtocol {    func fetchData() -> String}

class RealNetworkService: NetworkServiceProtocol { func fetchData() -> String { return "بيانات حقيقية من الخادم" }}

class MockNetworkService: NetworkServiceProtocol { func fetchData() -> String { return "بيانات اختبارية" }}

class DataManager { private let network: NetworkServiceProtocol

// يتم تمرير التبعية عبر init init(network: NetworkServiceProtocol) { self.network = network }

func load() -> String { return network.fetchData() }}

// الاستخدامlet realManager = DataManager(network: RealNetworkService())let mockManager = DataManager(network: MockNetworkService())


الإيجابيات: يظهر بوضوح التبعيات المطلوبة. الكائن جاهز للعمل فوراً. السلبيات: إذا كان هناك تبعيات كثيرة، يصبح المُهيئ ضخماً.



2. الحقن عبر الخاصية (Property Injection)

يتم تعيين التبعية بعد إنشاء الكائن. يُستخدم غالباً عندما تكون التبعية اختيارية أو يصعب الحصول عليها في وقت التهيئة.



class UserViewModel {    var apiService: NetworkServiceProtocol? // تبعية اختيارية

func loadUser() { apiServi

المدونات

توصيات الكتب