ما هو حقن التبعية في Swift ولماذا تحتاجه؟
\n\nحقن التبعية (Dependency Injection) أو DI هو أحد المبادئ الأساسية للتصميم في تطوير iOS الحديث. إذا كنت قد بدأت للتو رحلتك مع Swift، فربما واجهت بالفعل موقفًا حيث يقوم أحد الفئات بإنشاء كائنات من فئة أخرى مباشرة داخل نفسه. يُسمى هذا الاقتران المحكم (tight coupling)، وهذا يجعل الكود الخاص بك صعبًا في الاختبار والصيانة.
\n\nيحل حقن التبعية هذه المشكلة: بدلاً من أن يقوم الفئة بإنشاء تبعياته بنفسه، يتم "حقنها" من الخارج. هذا يجعل الكود أكثر مرونة وقابلية للاختبار ويتوافق مع مبدأ المسؤولية الواحدة (Single Responsibility) من SOLID.
\n\nفي هذه المقالة، سنشرح كيفية عمل حقن التبعية في Swift مع أمثلة عملية، ونوضح كيفية تطبيق هذه الممارسة في مشاريعك لنظامي iOS و macOS.
\n\nالأنواع الرئيسية لحقن التبعية في Swift
\n\nهناك ثلاث طرق رئيسية لحقن التبعيات في Swift. يعتمد اختيار الطريقة المحددة على بنية تطبيقك.
\n\n1. حقن المُنشئ (Constructor Injection)
\nالطريقة الأكثر شيوعًا والموصى بها. يتم تمرير التبعيات عبر init الخاص بالفئة. هذا يضمن أن الكائن دائمًا في حالة صالحة.
// بروتوكول للخدمة\nprotocol DataServiceProtocol {\n func fetchData() -> String\n}\n\n// التنفيذ الفعلي\nclass DataService: DataServiceProtocol {\n func fetchData() -> String {\n return "بيانات من الخادم"\n }\n}\n\n// الفئة التي تستخدم الخدمة\nclass ViewModel {\n private let dataService: DataServiceProtocol\n \n // يتم حقن التبعية عبر المُنشئ\n init(dataService: DataServiceProtocol) {\n self.dataService = dataService\n }\n \n func loadData() {\n let data = dataService.fetchData()\n print("تم التحميل: \\(data)")\n }\n}\n\n// الاستخدام\nlet service = DataService()\nlet viewModel = ViewModel(dataService: service)\nviewModel.loadData()\n\n2. حقن الخاصية (Property Injection)
\nيُستخدم عندما لا تكون التبعية إلزامية لعمل الكائن أو يمكن أن تتغير خلال دورة حياته. من المهم عدم نسيان تعيين الخاصية قبل الاستخدام.
\n\nclass NetworkManager {\n var urlSession: URLSession?\n \n func makeRequest() {\n guard let session = urlSession else {\n print("خطأ: الجلسة غير محددة")\n return\n }\n // العمل مع session\n print("تم تنفيذ الطلب عبر \\(session)")\n }\n}\n\n// الاستخدام\nlet manager = NetworkManager()\nmanager.urlSession = URLSession.shared // حقن التبعية\nmanager.makeRequest()\n\n3. حقن الطريقة (Method Injection)
\nمثالي عندما تكون التبعية مطلوبة فقط لتنفيذ طريقة معينة واحدة.
\n\nclass PaymentProcessor {\n func processPayment(amount: Double, using gateway: PaymentGatewayProtocol) -> Bool {\n // gateway يُستخدم هنا فقط\n return gateway.charge(amount: amount)\n }\n}\n\nprotocol PaymentGatewayProtocol {\n func charge(amount: Double) -> Bool\n}\n\nclass StripeGateway: PaymentGatewayProtocol {\n func charge(amount: Double) -> Bool {\n print("دفع \\(amount) عبر Stripe")\n return true\n }\n}\n\n// الاستخدام\nlet processor = PaymentProcessor()\nlet stripe = StripeGateway()\nlet result = processor.processPayment(amount: 99.99, using: stripe)\n\nلماذا يجب استخدام حقن التبعية في مشاريع iOS؟
\n\nيتجاهل العديد من مطوري Swift المبتدئين DI، معتبرين أنه تعقيد غير ضروري. ومع ذلك، في الممارسة العملية، تظهر الفوائد بسرعة كبيرة:
\n\n- \n
- تبسيط الاختبار (Unit Testing): يمكنك بسهولة استبدال الخدمات الحقيقية بـ