حاوية حقن التبعية Swift: Swinject لنظامي iOS/macOS

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

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

ابدأ الدورة

حاوية حقن التبعية للغة Swift (iOS/macOS): Swinject

في تطوير iOS و macOS الحديث باستخدام Swift، تلعب الأنماط المعمارية دورًا رئيسيًا في إنشاء كود قابل للصيانة والاختبار. واحدة من أقوى الأدوات لتنفيذ مبدأ عكس التبعيات (Dependency Inversion Principle) هي Swinject — حاوية DI خفيفة الوزن ولكنها وظيفية، مكتوبة بلغة Swift. تسمح Swinject بإدارة إنشاء الكائنات وتبعياتها بشكل مركزي، مما يريح المطور من البناء اليدوي لرسم بياني للكائنات.



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

حقن التبعية (DI) هي تقنية يحصل فيها الكائن على تبعياته من الخارج، بدلاً من إنشائها بنفسه. هذا يقلل من ترابط الكود ويبسط الاختبارات الوحدوية. ومع ذلك، في المشاريع الكبيرة، يؤدي الحقن اليدوي للتبعيات إلى كود ضخم. هنا تأتي حاوية DI للمساعدة، والتي:

  • تؤتمت إنشاء وربط الكائنات
  • تدير عمر الكائنات (singletons، نسخ جديدة)
  • تبسط استبدال التطبيقات (مثلًا للاختبارات)
  • تزيد من قابلية قراءة الكود وصيانته


تثبيت Swinject

يمكن تثبيت Swinject عبر Swift Package Manager أو CocoaPods أو Carthage. لـ SPM، أضف في Package.swift:

dependencies: [    .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0")]

أو عبر CocoaPods:

pod 'Swinject', '~> 2.8'


المفاهيم الأساسية لـ Swinject

تعتمد المكتبة على عدة مكونات رئيسية:

  • Container — المسجل والمحلل الرئيسي للتبعيات
  • Service — النوع الذي يتم تسجيله (عادةً بروتوكول أو كلاس)
  • Component — التطبيق المحدد للخدمة
  • Scope — يحدد عمر الكائن (transient, graph, container, weak)


مثال عملي: تسجيل وحل التبعيات

لنأخذ سيناريو نموذجيًا — تطبيق مع خدمة مصادقة ووحدة تحكم تستخدمها.

// بروتوكول الخدمةprotocol AuthServiceProtocol {    func login(username: String, password: String) -> Bool}

// التطبيقclass AuthService: AuthServiceProtocol { func login(username: String, password: String) -> Bool { // منطق المصادقة return username == "admin" && password == "1234" }}

// وحدة التحكم التي تعتمد على AuthServiceProtocolclass LoginViewController { private let authService: AuthServiceProtocol // الحقن عبر المُهيئ init(authService: AuthServiceProtocol) { self.authService = authService } func authenticate(user: String, pass: String) { if authService.login(username: user, password: pass) { print("دخول ناجح") } else { print("بيانات غير صحيحة") } }}

// إعداد الحاويةlet container = Container()container.register(AuthServiceProtocol.self) { _ in AuthService() }container.register(LoginViewController.self) { r in LoginViewController(authService: r.resolve(AuthServiceProtocol.self)!)}

// الاستخدامlet controller = container.resolve(LoginViewController.self)!controller.authenticate(user: "admin", pass: "1234") // دخول ناجح


إدارة دورة الحياة (Scopes)

تدعم Swinject أربعة نطاقات مدمجة:

  • .transient — يتم إنشاء نسخة جديدة في كل مرة (الافتراضي)
  • .graph — نسخة واحدة لكل رسم بياني للحل (يُستخدم افتراضيًا لمعظم الحالات)
  • .container — singleton داخل الحاوية
  • .weak — مرجع ضعيف، الكائن

توصيات